summaryrefslogtreecommitdiffstats
path: root/src/tpm12/tpm_delegate.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tpm12/tpm_delegate.c')
-rw-r--r--src/tpm12/tpm_delegate.c3944
1 files changed, 3944 insertions, 0 deletions
diff --git a/src/tpm12/tpm_delegate.c b/src/tpm12/tpm_delegate.c
new file mode 100644
index 0000000..37ebc02
--- /dev/null
+++ b/src/tpm12/tpm_delegate.c
@@ -0,0 +1,3944 @@
+/********************************************************************************/
+/* */
+/* Delegate Handler */
+/* Written by Ken Goldman */
+/* IBM Thomas J. Watson Research Center */
+/* $Id: tpm_delegate.c 4580 2011-06-10 17:55:41Z kgoldman $ */
+/* */
+/* (c) Copyright IBM Corporation 2006, 2010. */
+/* */
+/* All rights reserved. */
+/* */
+/* Redistribution and use in source and binary forms, with or without */
+/* modification, are permitted provided that the following conditions are */
+/* met: */
+/* */
+/* Redistributions of source code must retain the above copyright notice, */
+/* this list of conditions and the following disclaimer. */
+/* */
+/* Redistributions in binary form must reproduce the above copyright */
+/* notice, this list of conditions and the following disclaimer in the */
+/* documentation and/or other materials provided with the distribution. */
+/* */
+/* Neither the names of the IBM Corporation nor the names of its */
+/* contributors may be used to endorse or promote products derived from */
+/* this software without specific prior written permission. */
+/* */
+/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
+/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
+/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */
+/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
+/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
+/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */
+/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */
+/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */
+/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
+/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */
+/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+/********************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "tpm_auth.h"
+#include "tpm_crypto.h"
+#include "tpm_cryptoh.h"
+#include "tpm_debug.h"
+#include "tpm_digest.h"
+#include "tpm_error.h"
+#include "tpm_key.h"
+#include "tpm_pcr.h"
+#include "tpm_permanent.h"
+#include "tpm_process.h"
+#include "tpm_secret.h"
+
+#include "tpm_delegate.h"
+
+/*
+ TPM_DELEGATE_PUBLIC
+*/
+
+/* TPM_DelegatePublic_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_DelegatePublic_Init(TPM_DELEGATE_PUBLIC *tpm_delegate_public)
+{
+ printf(" TPM_DelegatePublic_Init:\n");
+ tpm_delegate_public->rowLabel = 0;
+ TPM_PCRInfoShort_Init(&(tpm_delegate_public->pcrInfo));
+ TPM_Delegations_Init(&(tpm_delegate_public->permissions));
+ tpm_delegate_public->familyID = 0;
+ tpm_delegate_public->verificationCount = 0;
+ return;
+}
+
+/* TPM_DelegatePublic_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ After use, call TPM_DelegatePublic_Delete() to free memory
+*/
+
+TPM_RESULT TPM_DelegatePublic_Load(TPM_DELEGATE_PUBLIC *tpm_delegate_public,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegatePublic_Load:\n");
+ /* check the tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_DELEGATE_PUBLIC, stream, stream_size);
+ }
+ /* load rowLabel */
+ if (rc == 0) {
+ rc = TPM_Load8(&(tpm_delegate_public->rowLabel), stream, stream_size);
+ }
+ /* load pcrInfo */
+ if (rc == 0) {
+ rc = TPM_PCRInfoShort_Load(&(tpm_delegate_public->pcrInfo), stream, stream_size, FALSE);
+ }
+ /* load permissions */
+ if (rc == 0) {
+ rc = TPM_Delegations_Load(&(tpm_delegate_public->permissions), stream, stream_size);
+ }
+ /* load the familyID */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_delegate_public->familyID), stream, stream_size);
+ }
+ /* load the verificationCount */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_delegate_public->verificationCount), stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_DelegatePublic_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DelegatePublic_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DELEGATE_PUBLIC *tpm_delegate_public)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegatePublic_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_PUBLIC);
+ }
+ /* store rowLabel */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, &(tpm_delegate_public->rowLabel),
+ sizeof(TPM_DELEGATE_LABEL));
+ }
+ /* store pcrInfo */
+ if (rc == 0) {
+ rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_delegate_public->pcrInfo), FALSE);
+ }
+ /* store permissions */
+ if (rc == 0) {
+ rc = TPM_Delegations_Store(sbuffer, &(tpm_delegate_public->permissions));
+ }
+ /* store familyID */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegate_public->familyID);
+ }
+ /* store verificationCount */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegate_public->verificationCount);
+ }
+ return rc;
+}
+
+/* TPM_DelegatePublic_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_DelegatePublic_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_DelegatePublic_Delete(TPM_DELEGATE_PUBLIC *tpm_delegate_public)
+{
+ printf(" TPM_DeleteDelegatePublic:\n");
+ if (tpm_delegate_public != NULL) {
+ TPM_PCRInfoShort_Delete(&(tpm_delegate_public->pcrInfo));
+ TPM_Delegations_Delete(&(tpm_delegate_public->permissions));
+ TPM_DelegatePublic_Init(tpm_delegate_public);
+ }
+ return;
+}
+
+/* TPM_DelegatePublic_Copy() copies the 'src' to the 'dest' structure
+
+*/
+
+TPM_RESULT TPM_DelegatePublic_Copy(TPM_DELEGATE_PUBLIC *dest,
+ TPM_DELEGATE_PUBLIC *src)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegatePublic_Copy:\n");
+ if (rc == 0) {
+ /* copy rowLabel */
+ dest->rowLabel = src->rowLabel;
+ /* copy pcrInfo */
+ rc = TPM_PCRInfoShort_Copy(&(dest->pcrInfo), &(src->pcrInfo));
+ }
+ if (rc == 0) {
+ /* copy permissions */
+ TPM_Delegations_Copy(&(dest->permissions), &(src->permissions));
+ /* copy familyID */
+ dest->familyID = src->familyID;
+ /* copy verificationCount */
+ dest->verificationCount = src->verificationCount;
+ }
+ return rc;
+}
+
+/*
+ TPM_DELEGATE_SENSITIVE
+*/
+
+/* TPM_DelegateSensitive_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_DelegateSensitive_Init(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive)
+{
+ printf(" TPM_DelegateSensitive_Init:\n");
+ TPM_Secret_Init(tpm_delegate_sensitive->authValue);
+ return;
+}
+
+/* TPM_DelegateSensitive_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ After use, call TPM_DelegateSensitive_Delete() to free memory
+*/
+
+TPM_RESULT TPM_DelegateSensitive_Load(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegateSensitive_Load:\n");
+ /* check the tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_DELEGATE_SENSITIVE, stream, stream_size);
+ }
+ /* load authValue */
+ if (rc == 0) {
+ rc = TPM_Secret_Load(tpm_delegate_sensitive->authValue, stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_DelegateSensitive_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DelegateSensitive_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegateSensitive_Store:\n");
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_SENSITIVE);
+ }
+ if (rc == 0) {
+ rc = TPM_Secret_Store(sbuffer, tpm_delegate_sensitive->authValue);
+ }
+ return rc;
+}
+
+/* TPM_DelegateSensitive_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_DelegateSensitive_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_DelegateSensitive_Delete(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive)
+{
+ printf(" TPM_DeleteDelegateSensitive:\n");
+ if (tpm_delegate_sensitive != NULL) {
+ TPM_DelegateSensitive_Init(tpm_delegate_sensitive);
+ }
+ return;
+}
+
+/* TPM_DelegateSensitive_DecryptEncData() decrypts 'sensitiveArea' to a stream using 'delegateKey'
+ and then deserializes the stream to a TPM_DELEGATE_SENSITIVE
+*/
+
+TPM_RESULT TPM_DelegateSensitive_DecryptEncData(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive,
+ TPM_SIZED_BUFFER *sensitiveArea,
+ TPM_SYMMETRIC_KEY_TOKEN delegateKey)
+{
+ TPM_RESULT rc = 0;
+ unsigned char *s1; /* decrypted sensitive data */
+ uint32_t s1_length;
+ unsigned char *stream; /* temp input stream */
+ uint32_t stream_size;
+
+ printf(" TPM_DelegateSensitive_DecryptEncData:\n");
+ s1 = NULL; /* freed @1 */
+ if (rc == 0) {
+ rc = TPM_SymmetricKeyData_Decrypt(&s1, /* decrypted data */
+ &s1_length, /* length decrypted data */
+ sensitiveArea->buffer,
+ sensitiveArea->size,
+ delegateKey);
+ }
+ if (rc == 0) {
+ stream = s1;
+ stream_size = s1_length;
+ rc = TPM_DelegateSensitive_Load(tpm_delegate_sensitive, &stream, &stream_size);
+ }
+ free(s1); /* @1 */
+ return rc;
+}
+
+/*
+ TPM_DELEGATIONS
+*/
+
+/* TPM_Delegations_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_Delegations_Init(TPM_DELEGATIONS *tpm_delegations)
+{
+ printf(" TPM_Delegations_Init:\n");
+ tpm_delegations->delegateType = TPM_DEL_KEY_BITS; /* any legal value */
+ tpm_delegations->per1 = 0;
+ tpm_delegations->per2 = 0;
+ return;
+}
+
+/* TPM_Delegations_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ After use, call TPM_DeleteDelegations() to free memory
+*/
+
+TPM_RESULT TPM_Delegations_Load(TPM_DELEGATIONS *tpm_delegations,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_Delegations_Load:\n");
+ /* check tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_DELEGATIONS, stream, stream_size);
+ }
+ /* load delegateType */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_delegations->delegateType), stream, stream_size);
+ }
+ /* load per1 */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_delegations->per1), stream, stream_size);
+ }
+ /* load per2 */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_delegations->per2), stream, stream_size);
+ }
+ /* validate parameters */
+ if (rc == 0) {
+ if (tpm_delegations->delegateType == TPM_DEL_OWNER_BITS) {
+ if (tpm_delegations->per1 & ~TPM_DELEGATE_PER1_MASK) {
+ printf("TPM_Delegations_Load: Error, owner per1 %08x\n", tpm_delegations->per1);
+ rc = TPM_BAD_PARAMETER;
+ }
+ if (tpm_delegations->per2 & ~TPM_DELEGATE_PER2_MASK) {
+ printf("TPM_Delegations_Load: Error, owner per2 %08x\n", tpm_delegations->per2);
+ rc = TPM_BAD_PARAMETER;
+ }
+ }
+ else if (tpm_delegations->delegateType == TPM_DEL_KEY_BITS) {
+ if (tpm_delegations->per1 & ~TPM_KEY_DELEGATE_PER1_MASK) {
+ printf("TPM_Delegations_Load: Error, key per1 %08x\n", tpm_delegations->per1);
+ rc = TPM_BAD_PARAMETER;
+ }
+ if (tpm_delegations->per2 & ~TPM_KEY_DELEGATE_PER2_MASK) {
+ printf("TPM_Delegations_Load: Error, key per2 %08x\n", tpm_delegations->per2);
+ rc = TPM_BAD_PARAMETER;
+ }
+ }
+ else {
+ printf("TPM_Delegations_Load: Error, delegateType %08x\n",
+ tpm_delegations->delegateType);
+ rc = TPM_BAD_PARAMETER;
+ }
+ }
+ return rc;
+}
+
+/* TPM_Delegations_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_Delegations_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DELEGATIONS *tpm_delegations)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_Delegations_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATIONS);
+ }
+ /* store delegateType */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegations->delegateType);
+ }
+ /* store per1 */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegations->per1);
+ }
+ /* store per2 */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegations->per2);
+ }
+ return rc;
+}
+
+/* TPM_Delegations_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_Delegations_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_Delegations_Delete(TPM_DELEGATIONS *tpm_delegations)
+{
+ printf(" TPM_Delegations_Delete:\n");
+ if (tpm_delegations != NULL) {
+ TPM_Delegations_Init(tpm_delegations);
+ }
+ return;
+}
+
+/* TPM_Delegations_Copy() copies the source to the destination
+ */
+
+void TPM_Delegations_Copy(TPM_DELEGATIONS *dest,
+ TPM_DELEGATIONS *src)
+{
+ dest->delegateType = src->delegateType;
+ dest->per1 = src->per1;
+ dest->per2 = src->per2;
+ return;
+}
+
+/* TPM_Delegations_CheckPermissionDelegation() verifies that the new delegation bits do not grant
+ more permissions then currently delegated. Otherwise return error TPM_AUTHFAIL.
+
+ An error occurs if a bit is set in newDelegations -> per and clear in currentDelegations -> per
+*/
+
+TPM_RESULT TPM_Delegations_CheckPermissionDelegation(TPM_DELEGATIONS *newDelegations,
+ TPM_DELEGATIONS *currentDelegations)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_Delegations_CheckPermissionDelegation:\n");
+ /* check per1 */
+ if (rc == 0) {
+ if (newDelegations->per1 & ~currentDelegations->per1) {
+ printf("TPM_Delegations_CheckPermissionDelegation: Error, "
+ "new per1 %08x current per1 %08x\n",
+ newDelegations->per1, currentDelegations->per1);
+ rc = TPM_AUTHFAIL;
+ }
+ }
+ /* check per2 */
+ if (rc == 0) {
+ if (newDelegations->per2 & ~currentDelegations->per2) {
+ printf("TPM_Delegations_CheckPermissionDelegation: Error, "
+ "new per1 %08x current per1 %08x\n",
+ newDelegations->per1, currentDelegations->per1);
+ rc = TPM_AUTHFAIL;
+ }
+ }
+ return rc;
+}
+
+/* TPM_Delegations_CheckPermission() verifies that the 'ordinal' has been delegated for execution
+ based on the TPM_DELEGATE_PUBLIC.
+
+ It verifies that the TPM_DELEGATIONS is appropriate for the entityType. Currently, only key or
+ owner authorization can be delegated.
+
+ It verifies that the TPM_DELEGATE_PUBLIC PCR's allow the delegation.
+*/
+
+TPM_RESULT TPM_Delegations_CheckPermission(tpm_state_t *tpm_state,
+ TPM_DELEGATE_PUBLIC *delegatePublic,
+ TPM_ENT_TYPE entityType, /* required */
+ TPM_COMMAND_CODE ordinal)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_Delegations_CheckPermission: ordinal %08x\n", ordinal);
+ if (rc == 0) {
+ switch (entityType) {
+ case TPM_ET_KEYHANDLE:
+ rc = TPM_Delegations_CheckKeyPermission(&(delegatePublic->permissions), ordinal);
+ break;
+ case TPM_ET_OWNER:
+ rc = TPM_Delegations_CheckOwnerPermission(&(delegatePublic->permissions), ordinal);
+ break;
+ default:
+ printf("TPM_Delegations_CheckPermission: Error, "
+ "DSAP session does not support entity type %02x\n",
+ entityType);
+ rc = TPM_AUTHFAIL;
+ break;
+ }
+ }
+ /* check that the TPM_DELEGATE_PUBLIC PCR's allow the delegation */
+ if (rc == 0) {
+ rc = TPM_PCRInfoShort_CheckDigest(&(delegatePublic->pcrInfo),
+ tpm_state->tpm_stclear_data.PCRS,
+ tpm_state->tpm_stany_flags.localityModifier);
+ }
+ return rc;
+}
+
+/* TPM_Delegations_CheckOwnerPermission() verifies that the 'ordinal' has been delegated for
+ execution based on the TPM_DELEGATIONS.
+*/
+
+TPM_RESULT TPM_Delegations_CheckOwnerPermission(TPM_DELEGATIONS *tpm_delegations,
+ TPM_COMMAND_CODE ordinal)
+{
+ TPM_RESULT rc = 0;
+ uint16_t ownerPermissionBlock; /* 0:unused, 1:per1 2:per2 */
+ uint32_t ownerPermissionPosition; /* owner permission bit position */
+
+ printf(" TPM_Delegations_CheckOwnerPermission: ordinal %08x\n", ordinal);
+ /* check that the TPM_DELEGATIONS structure is the correct type */
+ if (rc == 0) {
+ if (tpm_delegations->delegateType != TPM_DEL_OWNER_BITS) {
+ printf("TPM_Delegations_CheckOwnerPermission: Error,"
+ "Ordinal requires owner auth but delegateType is %08x\n",
+ tpm_delegations->delegateType);
+ rc = TPM_AUTHFAIL;
+ }
+ }
+ /* get the block and position in the block from the ordinals table */
+ if (rc == 0) {
+ rc = TPM_OrdinalTable_GetOwnerPermission(&ownerPermissionBlock,
+ &ownerPermissionPosition,
+ ordinal);
+ }
+ /* check that the permission bit is set in the TPM_DELEGATIONS bit map */
+ if (rc == 0) {
+ printf(" TPM_Delegations_CheckOwnerPermission: block %u position %u\n",
+ ownerPermissionBlock, ownerPermissionPosition);
+ switch (ownerPermissionBlock) {
+ case 1: /* per1 */
+ if (!(tpm_delegations->per1 & (1 << ownerPermissionPosition))) {
+ printf("TPM_Delegations_CheckOwnerPermission: Error, per1 %08x\n",
+ tpm_delegations->per1);
+ rc = TPM_AUTHFAIL;
+ }
+ break;
+ case 2: /* per2 */
+ if (!(tpm_delegations->per2 & (1 << ownerPermissionPosition))) {
+ printf("TPM_Delegations_CheckOwnerPermission: Error, per2 %08x\n",
+ tpm_delegations->per2);
+ rc = TPM_AUTHFAIL;
+ }
+ break;
+ default:
+ printf("TPM_Delegations_CheckOwnerPermission: Error, block not 1 or 2\n");
+ rc = TPM_AUTHFAIL;
+ break;
+ }
+ }
+ return rc;
+}
+
+/* TPM_Delegations_CheckKeyPermission() verifies that the 'ordinal' has been delegated for
+ execution based on the TPM_DELEGATIONS.
+*/
+
+TPM_RESULT TPM_Delegations_CheckKeyPermission(TPM_DELEGATIONS *tpm_delegations,
+ TPM_COMMAND_CODE ordinal)
+{
+ TPM_RESULT rc = 0;
+ uint16_t keyPermissionBlock; /* 0:unused, 1:per1 2:per2 */
+ uint32_t keyPermissionPosition; /* key permission bit position */
+
+ printf(" TPM_Delegations_CheckKeyPermission: ordinal %08x\n", ordinal);
+ /* check that the TPM_DELEGATIONS structure is the correct type */
+ if (rc == 0) {
+ if (tpm_delegations->delegateType != TPM_DEL_KEY_BITS) {
+ printf("TPM_Delegations_CheckKeyPermission: Error,"
+ "Ordinal requires key auth but delegateType is %08x\n",
+ tpm_delegations->delegateType);
+ rc = TPM_AUTHFAIL;
+ }
+ }
+ /* get the block and position in the block from the ordinals table */
+ if (rc == 0) {
+ rc = TPM_OrdinalTable_GetKeyPermission(&keyPermissionBlock,
+ &keyPermissionPosition,
+ ordinal);
+ }
+ /* check that the permission bit is set in the TPM_DELEGATIONS bit map */
+ if (rc == 0) {
+ printf(" TPM_Delegations_CheckKeyPermission: block %u position %u\n",
+ keyPermissionBlock, keyPermissionPosition);
+ switch (keyPermissionBlock) {
+ case 1: /* per1 */
+ if (!(tpm_delegations->per1 & (1 << keyPermissionPosition))) {
+ printf("TPM_Delegations_CheckKeyPermission: Error, per1 %08x\n",
+ tpm_delegations->per1);
+ rc = TPM_AUTHFAIL;
+ }
+ break;
+ case 2: /* per2 */
+ if (!(tpm_delegations->per2 & (1 << keyPermissionPosition))) {
+ printf("TPM_Delegations_CheckKeyPermission: Error, per2 %08x\n",
+ tpm_delegations->per2);
+ rc = TPM_AUTHFAIL;
+ }
+ break;
+ default:
+ printf("TPM_Delegations_CheckKeyPermission: Error, block not 1 or 2\n");
+ rc = TPM_AUTHFAIL;
+ break;
+ }
+ }
+ return rc;
+}
+
+/*
+ TPM_DELEGATE_OWNER_BLOB
+*/
+
+/* TPM_DelegateOwnerBlob_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_DelegateOwnerBlob_Init(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob)
+{
+ printf(" TPM_DelegateOwnerBlob_Init:\n");
+ TPM_DelegatePublic_Init(&(tpm_delegate_owner_blob->pub));
+ TPM_Digest_Init(tpm_delegate_owner_blob->integrityDigest);
+ TPM_SizedBuffer_Init(&(tpm_delegate_owner_blob->additionalArea));
+ TPM_SizedBuffer_Init(&(tpm_delegate_owner_blob->sensitiveArea));
+ return;
+}
+
+/* TPM_DelegateOwnerBlob_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_DelegateOwnerBlob_Init()
+ After use, call TPM_DelegateOwnerBlob_Delete() to free memory
+*/
+
+TPM_RESULT TPM_DelegateOwnerBlob_Load(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegateOwnerBlob_Load:\n");
+ /* check tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_DELEGATE_OWNER_BLOB, stream, stream_size);
+ }
+ /* load pub */
+ if (rc == 0) {
+ rc = TPM_DelegatePublic_Load(&(tpm_delegate_owner_blob->pub), stream, stream_size);
+ }
+ /* check that permissions are owner */
+ if (rc == 0) {
+ if (tpm_delegate_owner_blob->pub.permissions.delegateType != TPM_DEL_OWNER_BITS) {
+ printf("TPM_DelegateOwnerBlob_Load: Error, delegateType expected %08x found %08x\n",
+ TPM_DEL_OWNER_BITS, tpm_delegate_owner_blob->pub.permissions.delegateType);
+ rc = TPM_INVALID_STRUCTURE;
+ }
+ }
+ /* load integrityDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Load(tpm_delegate_owner_blob->integrityDigest, stream, stream_size);
+ }
+ /* load additionalArea */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Load(&(tpm_delegate_owner_blob->additionalArea), stream, stream_size);
+ }
+ /* load sensitiveArea */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Load(&(tpm_delegate_owner_blob->sensitiveArea), stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_DelegateOwnerBlob_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DelegateOwnerBlob_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegateOwnerBlob_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_OWNER_BLOB);
+ }
+ /* store pub */
+ if (rc == 0) {
+ rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_owner_blob->pub));
+ }
+ /* store integrityDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Store(sbuffer, tpm_delegate_owner_blob->integrityDigest);
+ }
+ /* store additionalArea */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_owner_blob->additionalArea));
+ }
+ /* store sensitiveArea */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_owner_blob->sensitiveArea));
+ }
+ return rc;
+}
+
+/* TPM_DelegateOwnerBlob_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_DelegateOwnerBlob_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_DelegateOwnerBlob_Delete(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob)
+{
+ printf(" TPM_DelegateOwnerBlob_Delete:\n");
+ if (tpm_delegate_owner_blob != NULL) {
+ TPM_DelegatePublic_Delete(&(tpm_delegate_owner_blob->pub));
+ TPM_SizedBuffer_Delete(&(tpm_delegate_owner_blob->additionalArea));
+ TPM_SizedBuffer_Delete(&(tpm_delegate_owner_blob->sensitiveArea));
+ TPM_DelegateOwnerBlob_Init(tpm_delegate_owner_blob);
+ }
+ return;
+}
+
+/*
+ TPM_DELEGATE_KEY_BLOB
+*/
+
+/* TPM_DelegateKeyBlob_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_DelegateKeyBlob_Init(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob)
+{
+ printf(" TPM_DelegateKeyBlob_Init:\n");
+ TPM_DelegatePublic_Init(&(tpm_delegate_key_blob->pub));
+ TPM_Digest_Init(tpm_delegate_key_blob->integrityDigest);
+ TPM_Digest_Init(tpm_delegate_key_blob->pubKeyDigest);
+ TPM_SizedBuffer_Init(&(tpm_delegate_key_blob->additionalArea));
+ TPM_SizedBuffer_Init(&(tpm_delegate_key_blob->sensitiveArea));
+ return;
+}
+
+/* TPM_DelegateKeyBlob_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_DelegateKeyBlob_Init()
+ After use, call TPM_DelegateKeyBlob_Delete() to free memory
+*/
+
+TPM_RESULT TPM_DelegateKeyBlob_Load(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegateKeyBlob_Load:\n");
+ /* check tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_DELG_KEY_BLOB, stream, stream_size);
+ }
+ /* load pub */
+ if (rc == 0) {
+ rc = TPM_DelegatePublic_Load(&(tpm_delegate_key_blob->pub), stream, stream_size);
+ }
+ /* check that permissions are key */
+ if (rc == 0) {
+ if (tpm_delegate_key_blob->pub.permissions.delegateType != TPM_DEL_KEY_BITS) {
+ printf("TPM_DelegateKeyBlob_Load: Error, delegateType expected %08x found %08x\n",
+ TPM_DEL_KEY_BITS, tpm_delegate_key_blob->pub.permissions.delegateType);
+ rc = TPM_INVALID_STRUCTURE;
+ }
+ }
+ /* load integrityDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Load(tpm_delegate_key_blob->integrityDigest, stream, stream_size);
+ }
+ /* load pubKeyDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Load(tpm_delegate_key_blob->pubKeyDigest, stream, stream_size);
+ }
+ /* load additionalArea */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Load(&(tpm_delegate_key_blob->additionalArea), stream, stream_size);
+ }
+ /* load sensitiveArea */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Load(&(tpm_delegate_key_blob->sensitiveArea), stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_DelegateKeyBlob_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DelegateKeyBlob_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegateKeyBlob_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELG_KEY_BLOB);
+ }
+ /* store pub */
+ if (rc == 0) {
+ rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_key_blob->pub));
+ }
+ /* store integrityDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Store(sbuffer, tpm_delegate_key_blob->integrityDigest);
+ }
+ /* store pubKeyDigest */
+ if (rc == 0) {
+ rc = TPM_Digest_Store(sbuffer, tpm_delegate_key_blob->pubKeyDigest);
+ }
+ /* store additionalArea */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_key_blob->additionalArea));
+ }
+ /* store sensitiveArea */
+ if (rc == 0) {
+ rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_key_blob->sensitiveArea));
+ }
+ return rc;
+}
+
+/* TPM_DelegateKeyBlob_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_DelegateKeyBlob_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_DelegateKeyBlob_Delete(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob)
+{
+ printf(" TPM_DelegateKeyBlob_Delete:\n");
+ if (tpm_delegate_key_blob != NULL) {
+ TPM_DelegatePublic_Delete(&(tpm_delegate_key_blob->pub));
+ TPM_SizedBuffer_Delete(&(tpm_delegate_key_blob->additionalArea));
+ TPM_SizedBuffer_Delete(&(tpm_delegate_key_blob->sensitiveArea));
+ TPM_DelegateKeyBlob_Init(tpm_delegate_key_blob);
+ }
+ return;
+}
+
+/*
+ TPM_FAMILY_TABLE
+*/
+
+/* TPM_FamilyTable_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_FamilyTable_Init(TPM_FAMILY_TABLE *tpm_family_table)
+{
+ size_t i;
+
+ printf(" TPM_FamilyTable_Init: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN);
+ for (i = 0 ; i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN ; i++) {
+ TPM_FamilyTableEntry_Init(&(tpm_family_table->famTableRow[i]));
+ }
+ return;
+}
+
+/* TPM_FamilyTable_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_FamilyTable_Init()
+ After use, call TPM_FamilyTable_Delete() to free memory
+*/
+
+TPM_RESULT TPM_FamilyTable_Load(TPM_FAMILY_TABLE *tpm_family_table,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+
+ printf(" TPM_FamilyTable_Load: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN);
+ for (i = 0 ; (rc == 0) && (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) ; i++) {
+ rc = TPM_FamilyTableEntry_Load(&(tpm_family_table->famTableRow[i]),
+ stream,
+ stream_size);
+ }
+ return rc;
+}
+
+/* TPM_FamilyTable_Store()
+
+ If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored.
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_FamilyTable_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_FAMILY_TABLE *tpm_family_table,
+ TPM_BOOL store_tag)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+
+ printf(" TPM_FamilyTable_Store: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN);
+ for (i = 0 ; (rc == 0) && (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) ; i++) {
+ rc = TPM_FamilyTableEntry_Store(sbuffer,
+ &(tpm_family_table->famTableRow[i]), store_tag);
+ }
+ return rc;
+}
+
+/* TPM_FamilyTable_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_FamilyTable_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_FamilyTable_Delete(TPM_FAMILY_TABLE *tpm_family_table)
+{
+ size_t i;
+
+ printf(" TPM_FamilyTable_Delete: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN);
+ if (tpm_family_table != NULL) {
+ for (i = 0 ; i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN ; i++) {
+ TPM_FamilyTableEntry_Delete(&(tpm_family_table->famTableRow[i]));
+ }
+ TPM_FamilyTable_Init(tpm_family_table);
+ }
+ return;
+}
+
+/* TPM_FamilyTable_GetEntry() searches all entries for the entry matching the familyID, and returns
+ the TPM_FAMILY_TABLE_ENTRY associated with the familyID.
+
+ Returns
+ 0 for success
+ TPM_BADINDEX if the familyID is not found
+*/
+
+TPM_RESULT TPM_FamilyTable_GetEntry(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, /* output */
+ TPM_FAMILY_TABLE *tpm_family_table,
+ TPM_FAMILY_ID familyID)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+ TPM_BOOL found;
+
+ printf(" TPM_FamilyTable_GetEntry: familyID %08x\n", familyID);
+ for (i = 0, found = FALSE ; (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) && !found ; i++) {
+ if (tpm_family_table->famTableRow[i].valid &&
+ (tpm_family_table->famTableRow[i].familyID == familyID)) { /* found */
+ found = TRUE;
+ *tpm_family_table_entry = &(tpm_family_table->famTableRow[i]);
+ }
+ }
+ if (!found) {
+ printf("TPM_FamilyTable_GetEntry: Error, familyID %08x not found\n", familyID);
+ rc = TPM_BADINDEX;
+ }
+ return rc;
+}
+
+/* TPM_FamilyTable_GetEnabledEntry() searches all entries for the entry matching the familyID, and
+ returns the TPM_FAMILY_TABLE_ENTRY associated with the familyID.
+
+ Similar to TPM_FamilyTable_GetEntry() but returns an error if the entry is disabled.
+
+ Returns
+ 0 for success
+ TPM_BADINDEX if the familyID is not found
+ TPM_DISABLED_CMD if the TPM_FAMILY_TABLE_ENTRY -> TPM_FAMFLAG_ENABLED is FALSE
+*/
+
+TPM_RESULT TPM_FamilyTable_GetEnabledEntry(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry,
+ TPM_FAMILY_TABLE *tpm_family_table,
+ TPM_FAMILY_ID familyID)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_FamilyTable_GetEnabledEntry: familyID %08x\n", familyID);
+ if (rc == 0) {
+ rc = TPM_FamilyTable_GetEntry(tpm_family_table_entry,
+ tpm_family_table,
+ familyID);
+ }
+ if (rc == 0) {
+ if (!((*tpm_family_table_entry)->flags & TPM_FAMFLAG_ENABLED)) {
+ printf("TPM_FamilyTable_GetEnabledEntry: Error, family %08x disabled\n", familyID);
+ rc = TPM_DISABLED_CMD;
+ }
+ }
+ return rc;
+}
+
+/* TPM_FamilyTable_IsSpace() returns success if an entry is available, an error if not.
+
+ If success, 'family_table_entry' holds the first free family table row.
+*/
+
+TPM_RESULT TPM_FamilyTable_IsSpace(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, /* output */
+ TPM_FAMILY_TABLE *tpm_family_table)
+{
+ size_t i;
+ TPM_BOOL isSpace;
+ TPM_RESULT rc = 0;
+
+
+ printf(" TPM_FamilyTable_IsSpace:\n");
+ for (i = 0, isSpace = FALSE ; i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN; i++) {
+ *tpm_family_table_entry = &(tpm_family_table->famTableRow[i]);
+ if (!((*tpm_family_table_entry)->valid)) {
+ printf(" TPM_FamilyTable_IsSpace: Found space at %lu\n", (unsigned long)i);
+ isSpace = TRUE;
+ break;
+ }
+ }
+ if (!isSpace) {
+ printf(" TPM_FamilyTable_IsSpace: Error, no space found\n");
+ rc = TPM_RESOURCES;
+ }
+ return rc;
+}
+
+/* TPM_FamilyTable_StoreValid() stores only the valid (occupied) entries
+
+ If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored.
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_FamilyTable_StoreValid(TPM_STORE_BUFFER *sbuffer,
+ const TPM_FAMILY_TABLE *tpm_family_table,
+ TPM_BOOL store_tag)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+
+ printf(" TPM_FamilyTable_StoreValid: \n");
+ for (i = 0 ; (rc == 0) && (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) ; i++) {
+ /* store only the valid rows */
+ if (tpm_family_table->famTableRow[i].valid) {
+ /* store only the publicly visible members */
+ printf(" TPM_FamilyTable_StoreValid: Entry %lu is valid\n", (unsigned long)i);
+ printf(" TPM_FamilyTable_StoreValid: Entry family ID is %08x\n",
+ tpm_family_table->famTableRow[i].familyID);
+ rc = TPM_FamilyTableEntry_StorePublic(sbuffer,
+ &(tpm_family_table->famTableRow[i]), store_tag);
+ }
+ }
+ return rc;
+}
+
+/*
+ TPM_FAMILY_TABLE_ENTRY
+*/
+
+/* TPM_FamilyTableEntry_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_FamilyTableEntry_Init(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry)
+{
+ printf(" TPM_FamilyTableEntry_Init:\n");
+ tpm_family_table_entry->familyLabel = 0;
+ tpm_family_table_entry->familyID = 0;
+ tpm_family_table_entry->verificationCount = 0;
+ tpm_family_table_entry->flags = 0;
+ tpm_family_table_entry->valid = FALSE;
+ return;
+}
+
+/* TPM_FamilyTableEntry_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_FamilyTableEntry_Init()
+ After use, call TPM_FamilyTableEntry_Delete() to free memory
+*/
+
+TPM_RESULT TPM_FamilyTableEntry_Load(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_FamilyTableEntry_Load:\n");
+ /* load tag */
+ /* the tag is not serialized when storing TPM_PERMANENT_DATA, to save NV space */
+ /* load familyLabel */
+ if (rc == 0) {
+ rc = TPM_Load8(&(tpm_family_table_entry->familyLabel), stream, stream_size);
+ }
+ /* load familyID */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_family_table_entry->familyID), stream, stream_size);
+ }
+ /* load verificationCount */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_family_table_entry->verificationCount), stream, stream_size);
+ }
+ /* load flags */
+ if (rc == 0) {
+ rc = TPM_Load32(&(tpm_family_table_entry->flags), stream, stream_size);
+ }
+ /* load valid */
+ if (rc == 0) {
+ rc = TPM_LoadBool(&(tpm_family_table_entry->valid), stream, stream_size);
+ }
+ if (rc == 0) {
+ printf(" TPM_FamilyTableEntry_Load: label %02x familyID %08x valid %u\n",
+ tpm_family_table_entry->familyLabel,
+ tpm_family_table_entry->familyID,
+ tpm_family_table_entry->valid);
+ }
+ return rc;
+}
+
+/* TPM_FamilyTableEntry_Store() stores all members of the structure
+
+ If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored.
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_FamilyTableEntry_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry,
+ TPM_BOOL store_tag)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_FamilyTableEntry_Store:\n");
+ /* store public, visible members */
+ if (rc == 0) {
+ rc = TPM_FamilyTableEntry_StorePublic(sbuffer, tpm_family_table_entry, store_tag);
+ }
+ /* store valid */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, &(tpm_family_table_entry->valid),
+ sizeof(TPM_BOOL));
+ }
+ return rc;
+}
+
+/* TPM_FamilyTableEntry_StorePublic() stores only the public, visible members of the structure
+
+ If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored.
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_FamilyTableEntry_StorePublic(TPM_STORE_BUFFER *sbuffer,
+ const TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry,
+ TPM_BOOL store_tag)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_FamilyTableEntry_StorePublic:\n");
+ /* store tag */
+ if ((rc == 0) && (store_tag)) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_FAMILY_TABLE_ENTRY);
+ }
+ /* store familyLabel */
+ if (rc == 0) {
+ TPM_Sbuffer_Append(sbuffer, &(tpm_family_table_entry->familyLabel),
+ sizeof(TPM_FAMILY_LABEL));
+ }
+ /* store familyID */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_family_table_entry->familyID);
+ }
+ /* store verificationCount */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_family_table_entry->verificationCount);
+ }
+ /* store flags */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, tpm_family_table_entry->flags);
+ }
+ return rc;
+}
+
+/* TPM_FamilyTableEntry_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_FamilyTableEntry_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_FamilyTableEntry_Delete(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry)
+{
+ printf(" TPM_FamilyTableEntry_Delete:\n");
+ if (tpm_family_table_entry != NULL) {
+ TPM_FamilyTableEntry_Init(tpm_family_table_entry);
+ }
+ return;
+}
+
+/*
+ TPM_DELEGATE_TABLE
+*/
+
+/* TPM_DelegateTable_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_DelegateTable_Init(TPM_DELEGATE_TABLE *tpm_delegate_table)
+{
+ size_t i;
+
+ printf(" TPM_DelegateTable_Init: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN);
+ for (i = 0 ; i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN ; i++) {
+ TPM_DelegateTableRow_Init(&(tpm_delegate_table->delRow[i]));
+ }
+ return;
+}
+
+/* TPM_DelegateTable_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_DelegateTable_Init()
+ After use, call TPM_DelegateTable_Delete() to free memory
+*/
+
+TPM_RESULT TPM_DelegateTable_Load(TPM_DELEGATE_TABLE *tpm_delegate_table,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+
+ printf(" TPM_DelegateTable_Load: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN);
+ for (i = 0 ; (rc == 0) && (i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) ; i++) {
+ rc = TPM_DelegateTableRow_Load(&(tpm_delegate_table->delRow[i]),
+ stream,
+ stream_size);
+ }
+ return rc;
+}
+
+/* TPM_DelegateTable_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DelegateTable_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DELEGATE_TABLE *tpm_delegate_table)
+{
+ TPM_RESULT rc = 0;
+ size_t i;
+
+ printf(" TPM_DelegateTable_Store: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN);
+ for (i = 0 ; (rc == 0) && (i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) ; i++) {
+ rc = TPM_DelegateTableRow_Store(sbuffer, &(tpm_delegate_table->delRow[i]));
+ }
+ return rc;
+}
+
+/* TPM_DelegateTable_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_DelegateTable_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_DelegateTable_Delete(TPM_DELEGATE_TABLE *tpm_delegate_table)
+{
+ size_t i;
+
+ printf(" TPM_DelegateTable_Delete: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN);
+ if (tpm_delegate_table != NULL) {
+ for (i = 0 ; i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN ; i++) {
+ TPM_DelegateTableRow_Delete(&(tpm_delegate_table->delRow[i]));
+ }
+ TPM_DelegateTable_Init(tpm_delegate_table);
+ }
+ return;
+}
+
+/* TPM_DelegateTable_StoreValid() store only the valid (occupied) entries. Each entry is prepended
+ with it's index.
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DelegateTable_StoreValid(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DELEGATE_TABLE *tpm_delegate_table)
+{
+ TPM_RESULT rc = 0;
+ uint32_t i;
+
+ printf(" TPM_DelegateTable_StoreValid:\n");
+ for (i = 0 ; (rc == 0) && (i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) ; i++) {
+ /* store only the valid rows */
+ if (tpm_delegate_table->delRow[i].valid) {
+ /* a. Write the TPM_DELEGATE_INDEX to delegateTable */
+ printf(" TPM_DelegateTable_StoreValid: Entry %u is valid\n", i);
+ printf(" TPM_DelegateTable_StoreValid: Entry family ID is %08x\n",
+ tpm_delegate_table->delRow[i].pub.familyID);
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append32(sbuffer, i);
+ }
+ /* b. Copy the TPM_DELEGATE_PUBLIC to delegateTable */
+ if (rc == 0) {
+ rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_table->delRow[i].pub));
+ }
+ }
+ }
+ return rc;
+}
+
+/* TPM_DelegateTable_GetRow() maps 'rowIndex' to a TPM_DELEGATE_TABLE_ROW in the delegate table.
+
+ The row may not have valid data.
+ */
+
+TPM_RESULT TPM_DelegateTable_GetRow(TPM_DELEGATE_TABLE_ROW **delegateTableRow,
+ TPM_DELEGATE_TABLE *tpm_delegate_table,
+ uint32_t rowIndex)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegateTable_GetRow: index %u\n", rowIndex);
+ if (rc == 0) {
+ if (rowIndex >= TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) {
+ printf("TPM_DelegateTable_GetRow: index %u out of range\n", rowIndex);
+ rc = TPM_BADINDEX;
+ }
+ }
+ if (rc == 0) {
+ *delegateTableRow = &(tpm_delegate_table->delRow[rowIndex]);
+ }
+ return rc;
+}
+
+/* TPM_DelegateTable_GetValidRow() maps 'rowIndex' to a TPM_DELEGATE_TABLE_ROW in the delegate
+ table.
+
+ The row must have valid data.
+ */
+
+TPM_RESULT TPM_DelegateTable_GetValidRow(TPM_DELEGATE_TABLE_ROW **delegateTableRow,
+ TPM_DELEGATE_TABLE *tpm_delegate_table,
+ uint32_t rowIndex)
+{
+ TPM_RESULT rc = 0;
+
+ if (rc == 0) {
+ rc = TPM_DelegateTable_GetRow(delegateTableRow,
+ tpm_delegate_table,
+ rowIndex);
+ }
+ if (rc == 0) {
+ *delegateTableRow = &(tpm_delegate_table->delRow[rowIndex]);
+ if (!(*delegateTableRow)->valid) {
+ printf("TPM_DelegateTable_GetValidRow: index %u invalid\n", rowIndex);
+ rc = TPM_BADINDEX;
+ }
+ }
+ return rc;
+}
+
+/*
+ TPM_DELEGATE_TABLE_ROW
+*/
+
+/* TPM_DelegateTableRow_Init()
+
+ sets members to default values
+ sets all pointers to NULL and sizes to 0
+ always succeeds - no return code
+*/
+
+void TPM_DelegateTableRow_Init(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row)
+{
+ printf(" TPM_DelegateTableRow_Init:\n");
+ TPM_DelegatePublic_Init(&(tpm_delegate_table_row->pub));
+ TPM_Secret_Init(tpm_delegate_table_row->authValue);
+ tpm_delegate_table_row->valid = FALSE;
+ return;
+}
+
+/* TPM_DelegateTableRow_Load()
+
+ deserialize the structure from a 'stream'
+ 'stream_size' is checked for sufficient data
+ returns 0 or error codes
+
+ Before use, call TPM_DelegateTableRow_Init()
+ After use, call TPM_DelegateTableRow_Delete() to free memory
+*/
+
+TPM_RESULT TPM_DelegateTableRow_Load(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row,
+ unsigned char **stream,
+ uint32_t *stream_size)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegateTableRow_Load:\n");
+ /* check the tag */
+ if (rc == 0) {
+ rc = TPM_CheckTag(TPM_TAG_DELEGATE_TABLE_ROW, stream, stream_size);
+ }
+ /* load pub */
+ if (rc == 0) {
+ rc = TPM_DelegatePublic_Load(&(tpm_delegate_table_row->pub), stream, stream_size);
+ }
+ /* load authValue */
+ if (rc == 0) {
+ rc = TPM_Secret_Load(tpm_delegate_table_row->authValue, stream, stream_size);
+ }
+ /* load valid */
+ if (rc == 0) {
+ rc = TPM_LoadBool(&(tpm_delegate_table_row->valid), stream, stream_size);
+ }
+ return rc;
+}
+
+/* TPM_DelegateTableRow_Store()
+
+ serialize the structure to a stream contained in 'sbuffer'
+ returns 0 or error codes
+*/
+
+TPM_RESULT TPM_DelegateTableRow_Store(TPM_STORE_BUFFER *sbuffer,
+ const TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row)
+{
+ TPM_RESULT rc = 0;
+
+ printf(" TPM_DelegateTableRow_Store:\n");
+ /* store tag */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_TABLE_ROW);
+ }
+ /* store pub */
+ if (rc == 0) {
+ rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_table_row->pub));
+ }
+ /* store authValue */
+ if (rc == 0) {
+ rc = TPM_Secret_Store(sbuffer, tpm_delegate_table_row->authValue);
+ }
+ /* store valid */
+ if (rc == 0) {
+ rc = TPM_Sbuffer_Append(sbuffer, &(tpm_delegate_table_row->valid), sizeof(TPM_BOOL));
+ }
+ return rc;
+}
+
+/* TPM_DelegateTableRow_Delete()
+
+ No-OP if the parameter is NULL, else:
+ frees memory allocated for the object
+ sets pointers to NULL
+ calls TPM_DelegateTableRow_Init to set members back to default values
+ The object itself is not freed
+*/
+
+void TPM_DelegateTableRow_Delete(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row)
+{
+ printf(" TPM_DelegateTableRow_Delete:\n");
+ if (tpm_delegate_table_row != NULL) {
+ TPM_DelegatePublic_Delete(&(tpm_delegate_table_row->pub));
+ TPM_DelegateTableRow_Init(tpm_delegate_table_row);
+ }
+ return;
+}
+
+/*
+ Processing Functions
+*/
+
+/* 19.1 TPM_Delegate_Manage rev 115
+
+ TPM_Delegate_Manage is the fundamental process for managing the Family tables, including
+ enabling/disabling Delegation for a selected Family. Normally TPM_Delegate_Manage must be
+ executed at least once (to create Family tables for a particular family) before any other type of
+ Delegation command in that family can succeed.
+
+ Delegate_Manage is authorized by the TPM Owner if an Owner is installed, because changing a table
+ is a privileged Owner operation. If no Owner is installed, Delegate_Manage requires no privilege
+ to execute. This does not disenfranchise an Owner, since there is no Owner, and simplifies
+ loading of tables during platform manufacture or on first-boot. Burn-out of TPM non-volatile
+ storage by inappropriate use is mitigated by the TPM's normal limits on NV-writes in the absence
+ of an Owner. Tables can be locked after loading, to prevent subsequent tampering, and only
+ unlocked by the Owner, his delegate, or the act of removing the Owner (even if there is no
+ Owner).
+
+ TPM_Delegate_Manage command is customized by opcode:
+
+ (1) TPM_FAMILY_ENABLE enables/disables use of a family and all the rows of the delegate table
+ belonging to that family,
+
+ (2) TPM_FAMILY_ADMIN can be used to prevent further management of the Tables until an Owner is
+ installed, or until the Owner is removed from the TPM. (Note that the Physical Presence command
+ TPM_ForceClear always enables further management, even if TPM_ForceClear is used when no Owner is
+ installed.)
+
+ (3) TPM_FAMILY_CREATE creates a new family.
+
+ (4) TPM_FAMILY_INVALIDATE invalidates an existing family.
+*/
+
+TPM_RESULT TPM_Process_DelegateManage(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_FAMILY_ID familyID; /* The familyID that is to be managed */
+ TPM_FAMILY_OPERATION opCode = 0; /* Operation to be performed by this command. */
+ TPM_SIZED_BUFFER opData; /* Data necessary to implement opCode */
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner
+ authentication. */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with
+ authHandle */
+ TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the
+ authorization session handle */
+ TPM_AUTHDATA ownerAuth; /* HMAC key: ownerAuth. */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_SECRET *hmacKey;
+ TPM_SECRET savedAuth; /* saved copy for response */
+ TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */
+ TPM_FAMILY_TABLE_ENTRY *familyRow = NULL; /* family table row containing familyID */
+ uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite;
+ /* temp for noOwnerNVWrite, initialize to
+ silence compiler */
+ TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */
+ TPM_BOOL writeAllNV = FALSE; /* flag to write back data */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_STORE_BUFFER retData; /* Returned data */
+
+ printf("TPM_Process_DelegateManage: Ordinal Entry\n");
+ TPM_SizedBuffer_Init(&opData); /* freed @1 */
+ TPM_Sbuffer_Init(&retData); /* freed @2 */
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get familyID parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&familyID, &command, &paramSize);
+ }
+ /* get opCode parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateManage: familyID %08x\n", familyID);
+ returnCode = TPM_Load32(&opCode, &command, &paramSize);
+ }
+ /* get opData parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateManage: opCode %u\n", opCode);
+ returnCode = TPM_SizedBuffer_Load(&opData, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_DelegateManage: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. If opCode != TPM_FAMILY_CREATE */
+ /* a. Locate familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row, return
+ TPM_BADINDEX if not found */
+ /* b. Set FR, a TPM_FAMILY_TABLE_ENTRY, to TPM_FAMILY_TABLE. famTableRow[familyRow] */
+ if ((returnCode == TPM_SUCCESS) && (opCode != TPM_FAMILY_CREATE)) {
+ printf("TPM_Process_DelegateManage: Not creating, get entry for familyID %08x\n",
+ familyID);
+ returnCode = TPM_FamilyTable_GetEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ familyID);
+ }
+ /* 2. If tag = TPM_TAG_RQU_AUTH1_COMMAND */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ /* a. Validate the command and parameters using ownerAuth, return TPM_AUTHFAIL on error */
+ returnCode =
+ TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_OWNER,
+ ordinal,
+ NULL,
+ &(tpm_state->tpm_permanent_data.ownerAuth),/* OIAP */
+ tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ /* make a copy of the HMAC key for the response, since it MAY be invalidated */
+ TPM_Secret_Copy(savedAuth, *hmacKey);
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* owner HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ ownerAuth); /* Authorization digest for input */
+ }
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ /* b. If the command is delegated (authHandle session type is TPM_PID_DSAP or through
+ ownerReference delegation) */
+ if ((auth_session_data->protocolID == TPM_PID_DSAP) ||
+ (tpm_state->tpm_stclear_data.ownerReference != TPM_KH_OWNER)) {
+ /* i. If opCode = TPM_FAMILY_CREATE */
+ /* (1) The TPM MUST ignore familyID */
+ /* ii. Else */
+ if (opCode != TPM_FAMILY_CREATE) {
+ /* get the TPM_DELEGATE_PUBLIC from the DSAP session */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic,
+ auth_session_data);
+ }
+ /* (1) Verify that the familyID associated with authHandle matches the familyID
+ parameter, return TPM_DELEGATE_FAMILY on error */
+ if (returnCode == TPM_SUCCESS) {
+ if (delegatePublic->familyID != familyID) {
+ printf("TPM_Process_DelegateManage: Error, familyID %08x should be %08x\n",
+ familyID, delegatePublic->familyID);
+ returnCode = TPM_DELEGATE_FAMILY;
+ }
+ }
+ }
+ }
+ }
+ /* 3. Else */
+ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) {
+ /* a. If TPM_PERMANENT_DATA -> ownerAuth is valid, return TPM_AUTHFAIL */
+ if (tpm_state->tpm_permanent_data.ownerInstalled) {
+ printf("TPM_Process_DelegateManage: Error, owner installed but no authorization\n");
+ returnCode = TPM_AUTHFAIL ;
+ }
+ }
+ /* b. If opCode != TPM_FAMILY_CREATE and FR -> flags -> TPM_DELEGATE_ADMIN_LOCK is TRUE, return
+ TPM_DELEGATE_LOCK */
+ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) {
+ if ((opCode != TPM_FAMILY_CREATE) && (familyRow->flags & TPM_DELEGATE_ADMIN_LOCK)) {
+ printf("TPM_Process_DelegateManage: Error, row locked\n");
+ returnCode = TPM_DELEGATE_LOCK;
+ }
+ }
+ /* c. Validate max NV writes without an owner */
+ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) {
+ /* i. Set NV1 to TPM_PERMANENT_DATA -> noOwnerNVWrite */
+ nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite;
+ /* ii. Increment NV1 by 1 */
+ nv1++;
+ /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */
+ if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) {
+ printf("TPM_Process_DelegateManage: Error, max NV writes %d w/o owner reached\n",
+ tpm_state->tpm_permanent_data.noOwnerNVWrite);
+ returnCode = TPM_MAXNVWRITES;
+ }
+ if (returnCode == TPM_SUCCESS){
+ /* iv. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */
+ /* NOTE Don't update the noOwnerNVWrite value until determining that the write will be
+ performed */
+ nv1Incremented = TRUE;
+ }
+ }
+ /* 4. The TPM invalidates sessions */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateManage: Invalidate sessions\n");
+ /* a. MUST invalidate all DSAP sessions */
+ /* b. MUST invalidate all OSAP sessions associated with the delegation table */
+ /* d. MAY invalidate any other session */
+ TPM_AuthSessions_TerminatexSAP(&continueAuthSession,
+ authHandle,
+ tpm_state->tpm_stclear_data.authSessions);
+ /* c. MUST set TPM_STCLEAR_DATA -> ownerReference to TPM_KH_OWNER */
+ tpm_state->tpm_stclear_data.ownerReference = TPM_KH_OWNER;
+ }
+ /*
+ 5. If opCode == TPM_FAMILY_CREATE
+ */
+ if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_CREATE)) {
+ printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_CREATE\n");
+ /* a. Validate that sufficient space exists within the TPM to store an additional family and
+ map F2 to the newly allocated space. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_FamilyTable_IsSpace(&familyRow, /* output */
+ &(tpm_state->tpm_permanent_data.familyTable));
+ }
+ /* b. Validate that opData is a TPM_FAMILY_LABEL */
+ if (returnCode == TPM_SUCCESS) {
+ /* i. If opDataSize != sizeof(TPM_FAMILY_LABEL) return TPM_BAD_PARAM_SIZE */
+ if (opData.size != sizeof(TPM_FAMILY_LABEL)) {
+ printf("TPM_Process_DelegateManage: Error, invalid opDataSize %u\n", opData.size);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* c. Map F2 to a TPM_FAMILY_TABLE_ENTRY */
+ /* NOTE Done by TPM_FamilyTable_IsSpace() */
+ /* i. Set F2 -> tag to TPM_TAG_FAMILY_TABLE_ENTRY */
+ /* NOTE Done by TPM_FamilyTableEntry_Init() */
+ if (returnCode == TPM_SUCCESS) {
+ /* ii. Set F2 -> familyLabel to opData */
+ familyRow->familyLabel = *(opData.buffer);
+ /* d. Increment TPM_PERMANENT_DATA -> lastFamilyID by 1 */
+ tpm_state->tpm_permanent_data.lastFamilyID++;
+ /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after NVRAM is written */
+ writeAllNV = TRUE;
+ /* e. Set F2 -> familyID = TPM_PERMANENT_DATA -> lastFamilyID */
+ familyRow->familyID = tpm_state->tpm_permanent_data.lastFamilyID;
+ /* f. Set F2 -> verificationCount = 1 */
+ familyRow->verificationCount = 1;
+ /* g. Set F2 -> flags -> TPM_FAMFLAG_ENABLED to FALSE */
+ familyRow->flags &= ~TPM_FAMFLAG_ENABLED;
+ /* h. Set F2 -> flags -> TPM_DELEGATE_ADMIN_LOCK to FALSE */
+ familyRow->flags &= ~TPM_DELEGATE_ADMIN_LOCK;
+ /* i. Set retDataSize = 4 */
+ /* j. Set retData = F2 -> familyID */
+ printf("TPM_Process_DelegateManage: Created familyID %08x\n", familyRow->familyID);
+ familyRow->valid = TRUE;
+ returnCode = TPM_Sbuffer_Append32(&retData, familyRow->familyID);
+ }
+ /* k. Return TPM_SUCCESS */
+ }
+ /* 6. If authHandle is of type DSAP then continueAuthSession MUST set to FALSE */
+ if ((returnCode == TPM_SUCCESS) && (opCode != TPM_FAMILY_CREATE) &&
+ (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { /* only if auth-1 */
+
+ if (auth_session_data->protocolID == TPM_PID_DSAP) {
+ continueAuthSession = FALSE;
+ }
+ }
+ /* 7. If opCode == TPM_FAMILY_ADMIN */
+ if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_ADMIN)) {
+ printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_ADMIN\n");
+ /* a. Validate that opDataSize == 1, and that opData is a Boolean value. */
+ if (returnCode == TPM_SUCCESS) {
+ if (opData.size != sizeof(TPM_BOOL)) {
+ printf("TPM_Process_DelegateManage: Error, invalid opDataSize %u\n", opData.size);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* b. Set (FR -> flags -> TPM_DELEGATE_ADMIN_LOCK) = opData */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateManage: TPM_FAMILY_ADMIN opData %02x\n",
+ opData.buffer[0]);
+ if (*(TPM_BOOL *)(opData.buffer)) {
+ familyRow->flags |= TPM_DELEGATE_ADMIN_LOCK;
+ }
+ else {
+ familyRow->flags &= ~TPM_DELEGATE_ADMIN_LOCK;
+ }
+ printf("TPM_Process_DelegateManage: new TPM_FAMILY_TABLE_ENTRY.flags %08x\n",
+ familyRow->flags);
+ /* c. Set retDataSize = 0 */
+ /* NOTE Done by TPM_Sbuffer_Init() */
+ /* d. Return TPM_SUCCESS */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ writeAllNV = TRUE;
+ }
+ }
+ /* 8. else If opflag == TPM_FAMILY_ENABLE */
+ if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_ENABLE)) {
+ printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_ENABLE\n");
+ /* a. Validate that opDataSize == 1, and that opData is a Boolean value. */
+ if (returnCode == TPM_SUCCESS) {
+ if (opData.size != sizeof(TPM_BOOL)) {
+ printf("TPM_Process_DelegateManage: Error, invalid opDataSize %u\n", opData.size);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* b. Set FR -> flags-> TPM_FAMFLAG_ENABLED = opData */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateManage: TPM_FAMILY_ENABLE opData %02x\n",
+ opData.buffer[0]);
+ if (*(TPM_BOOL *)(opData.buffer)) {
+ familyRow->flags |= TPM_FAMFLAG_ENABLED;
+ }
+ else {
+ familyRow->flags &= ~TPM_FAMFLAG_ENABLED;
+ }
+ printf("TPM_Process_DelegateManage: new TPM_FAMILY_TABLE_ENTRY.flags %08x\n",
+ familyRow->flags);
+ /* c. Set retDataSize = 0 */
+ /* NOTE Done by TPM_Sbuffer_Init() */
+ /* d. Return TPM_SUCCESS */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ writeAllNV = TRUE;
+ }
+ }
+ /* 9. else If opflag == TPM_FAMILY_INVALIDATE */
+ if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_INVALIDATE)) {
+ printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_INVALIDATE\n");
+ /* a. Invalidate all data associated with familyRow */
+ /* i. All data is all information pointed to by FR */
+ /* ii. return TPM_SELFTEST_FAILED on failure */
+ TPM_FamilyTableEntry_Delete(familyRow);
+ /* b.The TPM MAY invalidate delegate rows that contain the same familyID. */
+ /* c. Set retDataSize = 0 */
+ /* NOTE Done by TPM_Sbuffer_Init() */
+ /* d. Return TPM_SUCCESS */
+ writeAllNV = TRUE;
+ }
+ /* 10. Else return TPM_BAD_PARAMETER */
+ if (returnCode == TPM_SUCCESS) {
+ if ((opCode != TPM_FAMILY_CREATE) &&
+ (opCode != TPM_FAMILY_ADMIN) &&
+ (opCode != TPM_FAMILY_ENABLE) &&
+ (opCode != TPM_FAMILY_INVALIDATE)) {
+ printf("TPM_Process_DelegateManage: Error, bad opCode %08x\n", opCode);
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* if writing NV and this is a no owner NV write, update the count with the previously
+ incremented value */
+ if (returnCode == TPM_SUCCESS) {
+ if (writeAllNV && nv1Incremented) {
+ printf("TPM_Process_DelegateManage: noOwnerNVWrite %u\n", nv1);
+ tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1;
+ }
+ }
+ /* write back TPM_PERMANENT_DATA if required */
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ writeAllNV,
+ returnCode);
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_DelegateManage: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* append retDataSize and retData */
+ returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &retData);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Set(response,
+ savedAuth, /* saved HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_SizedBuffer_Delete(&opData); /* @1 */
+ TPM_Sbuffer_Delete(&retData); /* @2 */
+ return rcf;
+}
+
+/* 19.2 TPM_Delegate_CreateKeyDelegation rev 109
+
+ This command delegates privilege to use a key by creating a blob that can be used by TPM_DSAP.
+
+ There is no check for appropriateness of the key's key usage against the key permission
+ settings. If the key usage is incorrect, this command succeeds, but the delegated command will
+ fail.
+
+ These blobs CANNOT be used as input data for TPM_LoadOwnerDelegation because the internal TPM
+ delegate table can store owner delegations only.
+
+ (TPM_Delegate_CreateOwnerDelegation must be used to delegate Owner privilege.)
+
+ The use restrictions that may be present on the key pointed to by keyHandle are not enforced for
+ this command. Stated another way CreateKeyDelegation is not a use of the key.
+
+ The publicInfo -> familyID can specify a disabled family row. The family row is checked when the
+ key delegation is used in a DSAP session, not when it is created.
+*/
+
+TPM_RESULT TPM_Process_DelegateCreateKeyDelegation(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key. */
+ TPM_DELEGATE_PUBLIC publicInfo; /* The public information necessary to fill in the blob */
+ TPM_ENCAUTH delAuth; /* The encrypted new AuthData for the blob. The encryption
+ key is the shared secret from the authorization session
+ protocol.*/
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle
+ authorization */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */
+ TPM_BOOL continueAuthSession = TRUE; /* Ignored */
+ TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the use
+ of keyHandle. HMAC key: key.usageAuth */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_SECRET *hmacKey;
+ TPM_BOOL parentPCRStatus;
+ TPM_KEY *key = NULL; /* the key specified by keyHandle */
+ TPM_SECRET *keyUsageAuth;
+ TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */
+ TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */
+ TPM_DIGEST a1Auth;
+ TPM_DELEGATE_SENSITIVE m1DelegateSensitive;
+ TPM_STORE_BUFFER delegateSensitive_sbuffer;
+ TPM_DELEGATE_KEY_BLOB p1DelegateKeyBlob;
+
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_STORE_BUFFER blobSbuffer; /* The partially encrypted delegation information.
+ */
+
+ printf("TPM_Process_DelegateCreateKeyDelegation: Ordinal Entry\n");
+ TPM_DelegatePublic_Init(&publicInfo); /* freed @1 */
+ TPM_DelegateSensitive_Init(&m1DelegateSensitive); /* freed @2 */
+ TPM_Sbuffer_Init(&delegateSensitive_sbuffer); /* freed @3 */
+ TPM_DelegateKeyBlob_Init(&p1DelegateKeyBlob); /* freed @4 */
+ TPM_Sbuffer_Init(&blobSbuffer); /* freed @5 */
+ /*
+ get inputs
+ */
+ /* get keyHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&keyHandle, &command, &paramSize);
+ }
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get publicInfo parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateCreateKeyDelegation: keyHandle %08x\n", keyHandle);
+ returnCode = TPM_DelegatePublic_Load(&publicInfo, &command, &paramSize);
+ }
+ /* get delAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Load(delAuth, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ privAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_DelegateCreateKeyDelegation: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. Verify AuthData for the command and parameters using privAuth */
+ /* get the key corresponding to the keyHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle,
+ FALSE, /* not read-only */
+ FALSE, /* do not ignore PCRs */
+ FALSE); /* cannot use EK */
+ }
+ /* get keyHandle -> usageAuth */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key);
+ }
+ /* get the session data */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_OSAP,
+ TPM_ET_KEYHANDLE,
+ ordinal,
+ key,
+ NULL, /* OIAP */
+ key->tpm_store_asymkey->pubDataDigest); /* OSAP */
+ }
+ /* Validate the authorization */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ privAuth); /* Authorization digest for input */
+ }
+ /* 2. Locate publicInfo -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row,
+ return TPM_BADINDEX if not found */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_FamilyTable_GetEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ publicInfo.familyID);
+ }
+ /* 3. If the key authentication is in fact a delegation, then the TPM SHALL validate the command
+ and parameters using Delegation authorisation, then */
+ if ((returnCode == TPM_SUCCESS) && (auth_session_data->protocolID == TPM_PID_DSAP)) {
+ printf("TPM_Process_DelegateCreateKeyDelegation: Authentication is a delegation\n");
+ /* get the TPM_DELEGATE_PUBLIC from the DSAP session */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic,
+ auth_session_data);
+ }
+ /* a. Validate that authHandle -> familyID equals publicInfo -> familyID return
+ TPM_DELEGATE_FAMILY on error */
+ if (returnCode == TPM_SUCCESS) {
+ if (publicInfo.familyID != delegatePublic->familyID) {
+ printf("TPM_Process_DelegateCreateKeyDelegation: Error, "
+ "familyID %u should be %u\n",
+ publicInfo.familyID, delegatePublic->familyID);
+ returnCode = TPM_DELEGATE_FAMILY;
+ }
+ }
+ /* b. If TPM_FAMILY_TABLE.famTableRow[ authHandle -> familyID] -> flags ->
+ TPM_FAMFLAG_ENABLED is FALSE, return error TPM_DISABLED_CMD. */
+ if (returnCode == TPM_SUCCESS) {
+ if (!(familyRow->flags & TPM_FAMFLAG_ENABLED)) {
+ printf("TPM_Process_DelegateCreateKeyDelegation: Error, family %u disabled\n",
+ publicInfo.familyID);
+ returnCode = TPM_DISABLED_CMD;
+ }
+ }
+ /* c. Verify that the delegation bits in publicInfo do not grant more permissions then
+ currently delegated. Otherwise return error TPM_AUTHFAIL */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_Delegations_CheckPermissionDelegation(&(publicInfo.permissions),
+ &(delegatePublic->permissions));
+ }
+ }
+ /* 4. Check that publicInfo -> delegateType is TPM_DEL_KEY_BITS */
+ if (returnCode == TPM_SUCCESS) {
+ if (publicInfo.permissions.delegateType != TPM_DEL_KEY_BITS) {
+ printf("TPM_Process_DelegateCreateKeyDelegation: Error, "
+ "delegateType %08x not a key delegation\n",
+ publicInfo.permissions.delegateType);
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* 5. Verify that authHandle indicates an OSAP or DSAP session return TPM_INVALID_AUTHHANDLE on
+ error */
+ /* NOTE Done by TPM_AuthSessions_GetData() */
+ /* 6. Create a1 by decrypting delAuth according to the ADIP indicated by authHandle. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_Decrypt(a1Auth,
+ NULL,
+ delAuth,
+ auth_session_data,
+ NULL,
+ NULL,
+ FALSE); /* even and odd */
+ }
+ /* 7. Create h1 the SHA-1 of TPM_STORE_PUBKEY structure of the key pointed to by keyHandle */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_PrintFour("TPM_Process_DelegateCreateKeyDelegation: Decrypted a1", a1Auth);
+ returnCode = TPM_SHA1_GenerateStructure(p1DelegateKeyBlob.pubKeyDigest,
+ &(key->pubKey),
+ (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store);
+ }
+ /* 8. Create M1 a TPM_DELEGATE_SENSITIVE structure */
+ /* a. Set M1 -> tag to TPM_TAG_DELEGATE_SENSITIVE */
+ /* NOTE Done by TPM_DelegateSensitive_Init() */
+ /* b. Set M1 -> authValue to a1 */
+ if (returnCode == TPM_SUCCESS) {
+ TPM_Secret_Copy(m1DelegateSensitive.authValue, a1Auth);
+ /* c. The TPM MAY add additional information of a sensitive nature relative to the
+ delegation */
+ /* 9. Create M2 the encryption of M1 using TPM_DELEGATE_KEY */
+ /* serialize M1 */
+ returnCode = TPM_DelegateSensitive_Store(&delegateSensitive_sbuffer, &m1DelegateSensitive);
+ }
+ /* encrypt with delegate key */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateCreateKeyDelegation: Encrypting TPM_DELEGATE_SENSITIVE\n");
+ returnCode =
+ TPM_SymmetricKeyData_EncryptSbuffer(&(p1DelegateKeyBlob.sensitiveArea),
+ &delegateSensitive_sbuffer,
+ tpm_state->tpm_permanent_data.delegateKey);
+ }
+ /* 10. Create P1 a TPM_DELEGATE_KEY_BLOB */
+ /* a. Set P1 -> tag to TPM_TAG_DELG_KEY_BLOB */
+ /* NOTE Done by TPM_DelegateKeyBlob_Init() */
+ /* b. Set P1 -> pubKeyDigest to H1 */
+ /* NOTE Done by TPM_StorePubkey_GenerateDigest() */
+ /* c. Set P1 -> pub to PublicInfo */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegatePublic_Copy(&(p1DelegateKeyBlob.pub), &publicInfo);
+ }
+ /* d. Set P1 -> pub -> verificationCount to familyRow -> verificationCount */
+ if (returnCode == TPM_SUCCESS) {
+ p1DelegateKeyBlob.pub.verificationCount = familyRow->verificationCount;
+ /* e. Set P1 -> integrityDigest to NULL */
+ /* NOTE Done by TPM_DelegateKeyBlob_Init() */
+ /* f. The TPM sets additionalArea and additionalAreaSize appropriate for this TPM. The
+ information MAY include symmetric IV, symmetric mode of encryption and other data that
+ allows the TPM to process the blob in the future. */
+ /* g. Set P1 -> sensitiveSize to the size of M2 */
+ /* h. Set P1 -> sensitiveArea to M2 */
+ /* NOTE Encrypted directly into p1DelegateKeyBlob.sensitiveArea */
+ /* 11. Calculate H2 the HMAC of P1 using tpmProof as the secret */
+ /* 12. Set P1 -> integrityDigest to H2 */
+ /* NOTE It is safe to HMAC directly into TPM_DELEGATE_KEY_BLOB, since the structure
+ is serialized before the HMAC is performed */
+ returnCode = TPM_HMAC_GenerateStructure
+ (p1DelegateKeyBlob.integrityDigest, /* HMAC */
+ tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */
+ &p1DelegateKeyBlob, /* structure */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store); /* store function */
+ }
+ /* 13. Ignore continueAuthSession on input set continueAuthSession to FALSE on output */
+ if (returnCode == TPM_SUCCESS) {
+ continueAuthSession = FALSE;
+ }
+ /* 14. Return P1 as blob */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateKeyBlob_Store(&blobSbuffer, &p1DelegateKeyBlob);
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_DelegateCreateKeyDelegation: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* return blobSize and blob */
+ returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &blobSbuffer);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_DelegatePublic_Delete(&publicInfo); /* @1 */
+ TPM_DelegateSensitive_Delete(&m1DelegateSensitive); /* @2 */
+ TPM_Sbuffer_Delete(&delegateSensitive_sbuffer); /* @3 */
+ TPM_DelegateKeyBlob_Delete(&p1DelegateKeyBlob); /* @4 */
+ TPM_Sbuffer_Delete(&blobSbuffer); /* @5 */
+ return rcf;
+}
+
+/* 19.3 TPM_Delegate_CreateOwnerDelegation rev 98
+
+ TPM_Delegate_CreateOwnerDelegation delegates the Owner's privilege to use a set of command
+ ordinals, by creating a blob. Such blobs can be used as input data for TPM_DSAP or
+ TPM_Delegate_LoadOwnerDelegation.
+
+ TPM_Delegate_CreateOwnerDelegation includes the ability to void all existing delegations (by
+ incrementing the verification count) before creating the new delegation. This ensures that the
+ new delegation will be the only delegation that can operate at Owner privilege in this
+ family. This new delegation could be used to enable a security monitor (a local separate entity,
+ or remote separate entity, or local host entity) to reinitialize a family and perhaps perform
+ external verification of delegation settings. Normally the ordinals for a delegated security
+ monitor would include TPM_Delegate_CreateOwnerDelegation (this command) in order to permit the
+ monitor to create further delegations, and TPM_Delegate_UpdateVerification to reactivate some
+ previously voided delegations.
+
+ If the verification count is incremented and the new delegation does not delegate any privileges
+ (to any ordinals) at all, or uses an authorisation value that is then discarded, this family's
+ delegations are all void and delegation must be managed using actual Owner authorisation.
+
+ (TPM_Delegate_CreateKeyDelegation must be used to delegate privilege to use a key.)
+*/
+
+TPM_RESULT TPM_Process_DelegateCreateOwnerDelegation(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_BOOL increment; /* Flag dictates whether verificationCount will be
+ incremented */
+ TPM_DELEGATE_PUBLIC publicInfo; /* The public parameters for the blob */
+ TPM_ENCAUTH delAuth; /* The encrypted new AuthData for the blob. The encryption
+ key is the shared secret from the OSAP protocol.*/
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle TPM Owner authentication
+ */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */
+ TPM_BOOL continueAuthSession = TRUE; /* Ignored */
+ TPM_AUTHDATA ownerAuth; /* The authorization session digest. HMAC key:ownerAuth */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus = FALSE; /* audit the ordinal */
+ TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport
+ session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_SECRET *hmacKey;
+ TPM_SECRET savedAuth; /* saved copy for response */
+ TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */
+ TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */
+ TPM_BOOL writeAllNV = FALSE;
+ TPM_DIGEST a1Auth;
+ TPM_DELEGATE_SENSITIVE m1DelegateSensitive;
+ TPM_STORE_BUFFER delegateSensitive_sbuffer; /* serialization of delegateSensitive */
+ TPM_DELEGATE_OWNER_BLOB b1DelegateOwnerBlob;
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_STORE_BUFFER blobSbuffer; /* The partially encrypted delegation
+ information. */
+
+ printf("TPM_Process_DelegateCreateOwnerDelegation: Ordinal Entry\n");
+ TPM_DelegatePublic_Init(&publicInfo); /* freed @1 */
+ TPM_DelegateSensitive_Init(&m1DelegateSensitive); /* freed @2 */
+ TPM_Sbuffer_Init(&delegateSensitive_sbuffer); /* freed @3 */
+ TPM_DelegateOwnerBlob_Init(&b1DelegateOwnerBlob); /* freed @4 */
+ TPM_Sbuffer_Init(&blobSbuffer); /* freed @5 */
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get increment parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_LoadBool(&increment, &command, &paramSize);
+ }
+ /* get publicInfo parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateCreateOwnerDelegation: increment %02x\n", increment);
+ returnCode = TPM_DelegatePublic_Load(&publicInfo, &command, &paramSize);
+ }
+ /* get delAuth parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Load(delAuth, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_DelegateCreateOwnerDelegation: Error, "
+ "command has %u extra bytes\n", paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. The TPM SHALL authenticate the command using TPM Owner authentication. Return TPM_AUTHFAIL
+ on failure. */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_OSAP,
+ TPM_ET_OWNER,
+ ordinal,
+ NULL,
+ NULL, /* OIAP */
+ tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* make a copy of the HMAC key for the response, since it MAY be invalidated */
+ TPM_Secret_Copy(savedAuth, *hmacKey);
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* owner HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ ownerAuth); /* Authorization digest for input */
+ }
+ /* 2. Locate publicInfo -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate the
+ row return TPM_BADINDEX if not found */
+ /* a. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_FamilyTable_GetEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ publicInfo.familyID);
+ }
+ /* 3. If the TPM Owner authentication is in fact a delegation, then the TPM SHALL validate the
+ command and parameters using Delegation authorisation, then */
+ if ((returnCode == TPM_SUCCESS) && (auth_session_data->protocolID == TPM_PID_DSAP)) {
+ /* get the TPM_DELEGATE_PUBLIC from the DSAP session */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic,
+ auth_session_data);
+ }
+ /* a. Validate that authHandle -> familyID equals publicInfo -> familyID return
+ TPM_DELEGATE_FAMILY */
+ if (returnCode == TPM_SUCCESS) {
+ if (publicInfo.familyID != delegatePublic->familyID) {
+ printf("TPM_Process_DelegateCreateOwnerDelegation: Error, "
+ "familyID %u should be %u\n",
+ publicInfo.familyID, delegatePublic->familyID);
+ returnCode = TPM_DELEGATE_FAMILY;
+ }
+ }
+ /* b. If FR -> flags -> TPM_FAMFLAG_ENABLED is FALSE, return error TPM_DISABLED_CMD. */
+ if (returnCode == TPM_SUCCESS) {
+ if (!(familyRow->flags & TPM_FAMFLAG_ENABLED)) {
+ printf("TPM_Process_DelegateCreateOwnerDelegation: Error, family %u disabled\n",
+ publicInfo.familyID);
+ returnCode = TPM_DISABLED_CMD;
+ }
+ }
+ /* c. Verify that the delegation bits in publicInfo do not grant more permissions then
+ currently delegated. Otherwise return error TPM_AUTHFAIL */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_Delegations_CheckPermissionDelegation(&(publicInfo.permissions),
+ &(delegatePublic->permissions));
+ }
+ }
+ /* 4. Check that publicInfo -> delegateType is TPM_DEL_OWNER_BITS */
+ if (returnCode == TPM_SUCCESS) {
+ if (publicInfo.permissions.delegateType != TPM_DEL_OWNER_BITS) {
+ printf("TPM_Process_DelegateCreateOwnerDelegation: Error, bad delegateType %08x\n",
+ publicInfo.permissions.delegateType);
+ returnCode = TPM_BAD_PARAMETER;
+ }
+ }
+ /* 5. Verify that authHandle indicates an OSAP or DSAP session return TPM_INVALID_AUTHHANDLE on
+ error */
+ /* NOTE Done by TPM_AuthSessions_GetData() */
+ /* 7. Create a1 by decrypting delAuth according to the ADIP indicated by authHandle */
+ /* NOTE 7. moved before 6. because it needs the session data */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_Decrypt(a1Auth,
+ NULL,
+ delAuth,
+ auth_session_data,
+ NULL,
+ NULL,
+ FALSE); /* even and odd */
+ }
+ /* 6. If increment == TRUE */
+ if ((returnCode == TPM_SUCCESS) && increment) {
+ /* a. Increment FR -> verificationCount */
+ familyRow->verificationCount++;
+ writeAllNV = TRUE;
+ /* b. Set TPM_STCLEAR_DATA -> ownerReference to TPM_KH_OWNER */
+ tpm_state->tpm_stclear_data.ownerReference = TPM_KH_OWNER;
+ /* c. The TPM invalidates sessions */
+ /* i. MUST invalidate all DSAP sessions */
+ /* ii. MUST invalidate all OSAP sessions associated with the delegation table */
+ /* iii. MAY invalidate any other session */
+ TPM_AuthSessions_TerminatexSAP(&continueAuthSession,
+ authHandle,
+ tpm_state->tpm_stclear_data.authSessions);
+ }
+ /* 8. Create M1 a TPM_DELEGATE_SENSITIVE structure */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateCreateOwnerDelegation: Creating TPM_DELEGATE_SENSITIVE\n");
+ /* a. Set M1 -> tag to TPM_TAG_DELEGATE_SENSITIVE */
+ /* NOTE Done by TPM_DelegateSensitive_Init() */
+ /* b. Set M1 -> authValue to a1 */
+ TPM_Secret_Copy(m1DelegateSensitive.authValue, a1Auth);
+ /* c. Set other M1 fields as determined by the TPM vendor */
+ }
+ /* 9. Create M2 the encryption of M1 using TPM_DELEGATE_KEY */
+ /* serialize M1 */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateSensitive_Store(&delegateSensitive_sbuffer, &m1DelegateSensitive);
+ }
+ /* encrypt with delegate key */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateCreateOwnerDelegation: Encrypting TPM_DELEGATE_SENSITIVE\n");
+ returnCode =
+ TPM_SymmetricKeyData_EncryptSbuffer(&(b1DelegateOwnerBlob.sensitiveArea),
+ &delegateSensitive_sbuffer,
+ tpm_state->tpm_permanent_data.delegateKey);
+ }
+ /* 10. Create B1 a TPM_DELEGATE_OWNER_BLOB */
+ /* a. Set B1 -> tag to TPM_TAG_DELG_OWNER_BLOB */
+ /* NOTE Done by TPM_DelegateOwnerBlob_Init() */
+ /* b. Set B1 -> pub to publicInfo */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateCreateOwnerDelegation: Creating TPM_DELEGATE_OWNER_BLOB\n");
+ returnCode = TPM_DelegatePublic_Copy(&(b1DelegateOwnerBlob.pub), &publicInfo);
+ }
+ /* c. Set B1 -> sensitiveSize to the size of M2 */
+ /* d. Set B1 -> sensitiveArea to M2 */
+ /* NOTE Encrypted directly into b1DelegateOwnerBlob */
+ /* e. Set B1 -> integrityDigest to NULL */
+ /* NOTE Done by TPM_DelegateOwnerBlob_Init() */
+ if (returnCode == TPM_SUCCESS) {
+ /* f. Set B1 pub -> verificationCount to FR -> verificationCount */
+ b1DelegateOwnerBlob.pub.verificationCount = familyRow->verificationCount;
+ /* 11. The TPM sets additionalArea and additionalAreaSize appropriate for this TPM. The
+ information MAY include symmetric IV, symmetric mode of encryption and other data that
+ allows the TPM to process the blob in the future. */
+ /* 12. Create H1 the HMAC of B1 using tpmProof as the secret */
+ /* 13. Set B1 -> integrityDigest to H1 */
+ /* NOTE It is safe to HMAC directly into TPM_DELEGATE_OWNER_BLOB, since the structure
+ is serialized before the HMAC is performed */
+ returnCode = TPM_HMAC_GenerateStructure
+ (b1DelegateOwnerBlob.integrityDigest, /* HMAC */
+ tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */
+ &b1DelegateOwnerBlob, /* structure */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store); /* store function */
+ }
+ /* 14. Ignore continueAuthSession on input set continueAuthSession to FALSE on output */
+ if (returnCode == TPM_SUCCESS) {
+ continueAuthSession = FALSE;
+ }
+ /* 15. Return B1 as blob */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateOwnerBlob_Store(&blobSbuffer, &b1DelegateOwnerBlob);
+ }
+ /* write back TPM_PERMANENT_DATA if required */
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ writeAllNV,
+ returnCode);
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_DelegateCreateOwnerDelegation: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* return blobSize and blob */
+ returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &blobSbuffer);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ savedAuth, /* saved HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_DelegatePublic_Delete(&publicInfo); /* @1 */
+ TPM_DelegateSensitive_Delete(&m1DelegateSensitive); /* @2 */
+ TPM_Sbuffer_Delete(&delegateSensitive_sbuffer); /* @3 */
+ TPM_DelegateOwnerBlob_Delete(&b1DelegateOwnerBlob); /* @4 */
+ TPM_Sbuffer_Delete(&blobSbuffer); /* @5 */
+ return rcf;
+}
+
+/* 19.4 TPM_Delegate_LoadOwnerDelegation rev 109
+
+ This command loads a delegate table row blob into a non-volatile delegate table row.
+ Delegate_LoadOwnerDelegation can be used during manufacturing or on first boot (when no Owner is
+ installed), or after an Owner is installed. If an Owner is installed, Delegate_LoadOwnerDelegation
+ requires Owner authorisation, and sensitive information must be encrypted.
+
+ Burn-out of TPM non-volatile storage by inappropriate use is mitigated by the TPM's normal limits
+ on NV- writes in the absence of an Owner. Tables can be locked after loading using
+ TPM_Delegate_Manage, to prevent subsequent tampering.
+
+ A management system outside the TPM is expected to manage the delegate table rows stored on the
+ TPM, and can overwrite any previously stored data. There is no way to explicitly delete a
+ delegation entry. A new entry can overwrite an invalid entry.
+
+ This command cannot be used to load key delegation blobs into the TPM
+*/
+
+TPM_RESULT TPM_Process_DelegateLoadOwnerDelegation(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_DELEGATE_INDEX index; /* The index of the delegate row to be written */
+ uint32_t blobSize; /* The size of the delegate blob */
+ TPM_DELEGATE_OWNER_BLOB d1Blob; /* Delegation information, including encrypted
+ portions as appropriate */
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle TPM Owner
+ authentication */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with
+ authHandle */
+ TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the
+ authorization session handle */
+ TPM_AUTHDATA ownerAuth; /* The authorization session digest. HMAC
+ key:ownerAuth */
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus = FALSE; /* audit the ordinal */
+ TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport
+ session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_SECRET *hmacKey;
+ TPM_SECRET savedAuth; /* saved copy for response */
+ TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */
+ TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */
+ TPM_DELEGATE_SENSITIVE s1DelegateSensitive;
+ TPM_DELEGATE_TABLE_ROW *delegateTableRow;
+ unsigned char *stream;
+ uint32_t stream_size;
+ uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite;
+ /* temp for noOwnerNVWrite, initialize to
+ silence compiler */
+ TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */
+ TPM_BOOL writeAllNV = FALSE; /* flag to write back data */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_DelegateLoadOwnerDelegation: Ordinal Entry\n");
+ TPM_DelegateOwnerBlob_Init(&d1Blob); /* freed @1 */
+ TPM_DelegateSensitive_Init(&s1DelegateSensitive); /* freed @2 */
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get index parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Load32(&index, &command, &paramSize);
+ }
+ /* get blobSize parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: index %u\n", index);
+ returnCode = TPM_Load32(&blobSize, &command, &paramSize);
+ }
+ /* get blob parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateOwnerBlob_Load(&d1Blob, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag10(tag);
+ }
+ /* get the optional 'below the line' authorization parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. Map blob to D1 a TPM_DELEGATE_OWNER_BLOB. */
+ /* a. Validate that D1 -> tag == TPM_TAG_DELEGATE_OWNER_BLOB */
+ /* Done by TPM_DelegateOwnerBlob_Load() */
+ /* 2. Locate D1 -> pub -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row,
+ return TPM_BADINDEX if not found */
+ /* 3. Set FR to TPM_FAMILY_TABLE -> famTableRow[familyRow] */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_FamilyTable_GetEnabledEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ d1Blob.pub.familyID);
+ }
+ /* 4. If TPM Owner is installed */
+ if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) {
+ /* a. Validate the command and parameters using TPM Owner authorization, return
+ TPM_AUTHFAIL on error */
+ if (returnCode == TPM_SUCCESS) {
+ if (tag != TPM_TAG_RQU_AUTH1_COMMAND) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: Error, "
+ "owner installed but no authorization\n");
+ returnCode = TPM_AUTHFAIL;
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode =
+ TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_OWNER,
+ ordinal,
+ NULL,
+ &(tpm_state->tpm_permanent_data.ownerAuth),/* OIAP */
+ tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* make a copy of the HMAC key for the response, since it MAY be invalidated */
+ TPM_Secret_Copy(savedAuth, *hmacKey);
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* owner HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ ownerAuth); /* Authorization digest for input */
+ }
+ /* b. If the command is delegated (authHandle session type is TPM_PID_DSAP or through
+ ownerReference delegation), verify that D1 -> pub -> familyID matches authHandle ->
+ familyID, on error return TPM_DELEGATE_FAMILY */
+ if ((returnCode == TPM_SUCCESS) &&
+ ((auth_session_data->protocolID == TPM_PID_DSAP) ||
+ (tpm_state->tpm_stclear_data.ownerReference != TPM_KH_OWNER))) {
+ /* get the TPM_DELEGATE_PUBLIC from the DSAP session */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic,
+ auth_session_data);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (d1Blob.pub.familyID != delegatePublic->familyID) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: Error, "
+ "familyID %u should be %u\n",
+ d1Blob.pub.familyID, delegatePublic->familyID);
+ returnCode = TPM_DELEGATE_FAMILY;
+ }
+ }
+ }
+ }
+ /* 5. Else */
+ if ((returnCode == TPM_SUCCESS) && !tpm_state->tpm_permanent_data.ownerInstalled) {
+ /* a. If FR -> flags -> TPM_DELEGATE_ADMIN_LOCK is TRUE return TPM_DELEGATE_LOCK */
+ if (returnCode == TPM_SUCCESS) {
+ if (familyRow->flags & TPM_DELEGATE_ADMIN_LOCK) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: Error, row locked\n");
+ returnCode = TPM_DELEGATE_LOCK;
+ }
+ }
+ /* b. Validate max NV writes without an owner */
+ if (returnCode == TPM_SUCCESS) {
+ /* i. Set NV1 to PD -> noOwnerNVWrite */
+ nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite;
+ /* ii. Increment NV1 by 1 */
+ nv1++;
+ /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */
+ if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: Error, "
+ "max NV writes %d w/o owner reached\n",
+ tpm_state->tpm_permanent_data.noOwnerNVWrite);
+ returnCode = TPM_MAXNVWRITES;
+ }
+ }
+ /* iv. Set PD -> noOwnerNVWrite to NV1 */
+ if (returnCode == TPM_SUCCESS) {
+ /* NOTE Don't update the noOwnerNVWrite value until determining that the write will be
+ performed */
+ nv1Incremented = TRUE;
+ }
+ }
+ /* 6. If FR -> flags -> TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */
+ /* NOTE Done by TPM_FamilyTable_GetEnabledEntry() */
+ /* 7. If TPM Owner is installed, validate the integrity of the blob */
+ if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: Checking integrityDigest\n");
+ /* a. Copy D1 -> integrityDigest to H2 */
+ /* b. Set D1 -> integrityDigest to NULL */
+ /* c. Create H3 the HMAC of D1 using tpmProof as the secret */
+ /* d. Compare H2 to H3, return TPM_AUTHFAIL on mismatch */
+ returnCode = TPM_HMAC_CheckStructure
+ (tpm_state->tpm_permanent_data.tpmProof, /* key */
+ &d1Blob, /* structure */
+ d1Blob.integrityDigest, /* expected */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store, /* store function */
+ TPM_AUTHFAIL); /* error code */
+ }
+ /* 8. If TPM Owner is installed, create S1 a TPM_DELEGATE_SENSITIVE area by decrypting D1 ->
+ sensitiveArea using TPM_DELEGATE_KEY. */
+ if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) {
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: Decrypting sensitiveArea\n");
+ returnCode =
+ TPM_DelegateSensitive_DecryptEncData(&s1DelegateSensitive, /* decrypted data */
+ &(d1Blob.sensitiveArea), /* encrypted */
+ tpm_state->tpm_permanent_data.delegateKey);
+ }
+ }
+ /* 8. Otherwise set S1 = D1 -> sensitiveArea */
+ if ((returnCode == TPM_SUCCESS) && !tpm_state->tpm_permanent_data.ownerInstalled) {
+ stream = d1Blob.sensitiveArea.buffer;
+ stream_size = d1Blob.sensitiveArea.size;
+ returnCode = TPM_DelegateSensitive_Load(&s1DelegateSensitive, &stream, &stream_size);
+ }
+ /* 9. Validate S1 */
+ /* a. Validate that S1 -> tag == TPM_TAG_DELEGATE_SENSITIVE, return TPM_INVALID_STRUCTURE on
+ error */
+ /* NOTE Done by TPM_DelegateSensitive_Load() */
+ /* 10. Validate that index is a valid value for delegateTable, return TPM_BADINDEX on error */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateTable_GetRow(&delegateTableRow,
+ &(tpm_state->tpm_permanent_data.delegateTable),
+ index);
+ }
+ /* 11. The TPM invalidates sessions */
+ if (returnCode == TPM_SUCCESS) {
+ /* a. MUST invalidate all DSAP sessions */
+ /* b. MUST invalidate all OSAP sessions associated with the delegation table */
+ /* c. MAY invalidate any other session */
+ TPM_AuthSessions_TerminatexSAP(&continueAuthSession,
+ authHandle,
+ tpm_state->tpm_stclear_data.authSessions);
+ }
+ /* 12. Copy data to the delegate table row */
+ if (returnCode == TPM_SUCCESS) {
+ /* a. Copy the TPM_DELEGATE_PUBLIC from D1 -> pub to TPM_DELEGATE_TABLE -> delRow[index] ->
+ pub. */
+ returnCode = TPM_DelegatePublic_Copy(&delegateTableRow->pub, &(d1Blob.pub));
+ writeAllNV = TRUE;
+ }
+ if (returnCode == TPM_SUCCESS) {
+ delegateTableRow->valid = TRUE;
+ /* b. Copy the TPM_SECRET from S1 -> authValue to TPM_DELEGATE_TABLE -> delRow[index] ->
+ authValue. */
+ TPM_Secret_Copy(delegateTableRow->authValue, s1DelegateSensitive.authValue);
+ /* c. Set TPM_STCLEAR_DATA-> ownerReference to TPM_KH_OWNER */
+ tpm_state->tpm_stclear_data.ownerReference = TPM_KH_OWNER;
+ }
+ if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) {
+ /* d. If authHandle is of type DSAP then continueAuthSession MUST set to FALSE */
+ if (auth_session_data->protocolID == TPM_PID_DSAP) {
+ continueAuthSession = FALSE;
+ }
+ }
+ /* if writing NV and this is a no owner NV write, update the count with the previously
+ incremented value */
+ if (returnCode == TPM_SUCCESS) {
+ if (writeAllNV && nv1Incremented) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: noOwnerNVWrite %u\n", nv1);
+ tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1;
+ }
+ }
+ /* write back TPM_PERMANENT_DATA */
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ writeAllNV,
+ returnCode);
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_DelegateLoadOwnerDelegation: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) {
+ returnCode = TPM_AuthParams_Set(response,
+ savedAuth, /* saved HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_DelegateOwnerBlob_Delete(&d1Blob); /* @1 */
+ TPM_DelegateSensitive_Delete(&s1DelegateSensitive); /* @2 */
+ return rcf;
+}
+
+/* 19.5 TPM_Delegate_ReadTable rev 87
+
+ This command is used to read from the TPM the public contents of the family and delegate tables
+ that are stored on the TPM. Such data is required during external verification of tables.
+
+ There are no restrictions on the execution of this command; anyone can read this information
+ regardless of the state of the PCRs, regardless of whether they know any specific AuthData value
+ and regardless of whether or not the enable and admin bits are set one way or the other.
+*/
+
+TPM_RESULT TPM_Process_DelegateReadTable(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_STORE_BUFFER familySbuffer; /* Array of TPM_FAMILY_TABLE_ENTRY
+ elements */
+ TPM_STORE_BUFFER delegateSbuffer; /* Array of TPM_DELEGATE_INDEX and
+ TPM_DELEGATE_PUBLIC elements */
+
+ printf("TPM_Process_DelegateReadTable: Ordinal Entry\n");
+ TPM_Sbuffer_Init(&familySbuffer); /* freed @1 */
+ TPM_Sbuffer_Init(&delegateSbuffer); /* freed @2 */
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_DelegateReadTable: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* 1. Set familyTableSize to the number of valid families on the TPM times
+ sizeof(TPM_FAMILY_TABLE_ELEMENT). */
+ /* NOTE Done below by TPM_Sbuffer_AppendAsSizedBuffer() */
+ /* 2. Copy the valid entries in the internal family table to the output array familyTable */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_FamilyTable_StoreValid(&familySbuffer,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ TRUE); /* standard, store the tag */
+ }
+ /* 3. Set delegateTableSize to the number of valid delegate table entries on the TPM times
+ (sizeof(TPM_DELEGATE_PUBLIC) + 4). */
+ /* NOTE Done below by TPM_Sbuffer_AppendAsSizedBuffer() */
+ /* 4. For each valid entry */
+ /* a. Write the TPM_DELEGATE_INDEX to delegateTable */
+ /* b. Copy the TPM_DELEGATE_PUBLIC to delegateTable */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateTable_StoreValid(&delegateSbuffer,
+ &(tpm_state->tpm_permanent_data.delegateTable));
+ }
+ /* 5. Return TPM_SUCCESS */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_DelegateReadTable: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* append familyTableSize and familyTable */
+ returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &familySbuffer);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* append delegateTableSize and delegateTable */
+ returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &delegateSbuffer);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /*
+ cleanup
+ */
+ TPM_Sbuffer_Delete(&familySbuffer); /* @1 */
+ TPM_Sbuffer_Delete(&delegateSbuffer); /* @2 */
+ return rcf;
+}
+
+/* 19.6 TPM_Delegate_UpdateVerification rev 87
+
+ UpdateVerification sets the verificationCount in an entity (a blob or a delegation row) to the
+ current family value, in order that the delegations represented by that entity will continue to
+ be accepted by the TPM.
+*/
+
+TPM_RESULT TPM_Process_DelegateUpdateVerification(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_SIZED_BUFFER inputData; /* TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB or
+ TPM_DELEGATE_INDEX */
+ TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner
+ authentication. */
+ TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */
+ TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization
+ session handle */
+ TPM_AUTHDATA ownerAuth; /* Authorization HMAC key: ownerAuth. */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus = FALSE; /* audit the ordinal */
+ TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport
+ session */
+ TPM_BOOL authHandleValid = FALSE;
+ TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */
+ TPM_SECRET *hmacKey = NULL;
+ unsigned char *stream; /* temp input stream */
+ uint32_t stream_size;
+ TPM_STRUCTURE_TAG d1Tag; /* input structure tag */
+ TPM_DELEGATE_INDEX d1DelegateIndex;
+ TPM_DELEGATE_OWNER_BLOB d1DelegateOwnerBlob;
+ TPM_DELEGATE_KEY_BLOB d1DelegateKeyBlob;
+ TPM_DELEGATE_TABLE_ROW *d1DelegateTableRow = NULL;
+ TPM_FAMILY_ID familyID = 0;
+ TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */
+ TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */
+ TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+ TPM_STORE_BUFFER outputDataSbuffer; /* TPM_DELEGATE_KEY_BLOB or
+ TPM_DELEGATE_OWNER_BLOB */
+
+ printf("TPM_Process_DelegateUpdateVerification: Ordinal Entry\n");
+ TPM_SizedBuffer_Init(&inputData); /* freed @1 */
+ TPM_DelegateOwnerBlob_Init(&d1DelegateOwnerBlob); /* freed @2 */
+ TPM_DelegateKeyBlob_Init(&d1DelegateKeyBlob); /* freed @3 */
+ TPM_Sbuffer_Init(&outputDataSbuffer); /* freed @4 */
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get inputData parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&inputData, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag1(tag);
+ }
+ /* get the 'below the line' authorization parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Get(&authHandle,
+ &authHandleValid,
+ nonceOdd,
+ &continueAuthSession,
+ ownerAuth,
+ &command, &paramSize);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_DelegateUpdateVerification: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /* do not terminate sessions if the command did not parse correctly */
+ if (returnCode != TPM_SUCCESS) {
+ authHandleValid = FALSE;
+ }
+ /*
+ Processing
+ */
+ /* 1. Verify the TPM Owner, directly or indirectly through delegation, authorizes the command
+ and parameters, on error return TPM_AUTHFAIL */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessions_GetData(&auth_session_data,
+ &hmacKey,
+ tpm_state,
+ authHandle,
+ TPM_PID_NONE,
+ TPM_ET_OWNER,
+ ordinal,
+ NULL,
+ &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */
+ tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */
+ }
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Authdata_Check(tpm_state,
+ *hmacKey, /* owner HMAC key */
+ inParamDigest,
+ auth_session_data, /* authorization session */
+ nonceOdd, /* Nonce generated by system
+ associated with authHandle */
+ continueAuthSession,
+ ownerAuth); /* Authorization digest for input */
+ }
+ /* 2. Determine the type of inputData (TPM_DELEGATE_TABLE_ROW or TPM_DELEGATE_OWNER_BLOB
+ or TPM_DELEGATE_KEY_BLOB) and map D1 to that structure */
+ if (returnCode == TPM_SUCCESS) {
+ /* use a temporary copy so the original values are not moved */
+ stream = inputData.buffer;
+ stream_size = inputData.size;
+ /* the inputData is either a table index or a blob */
+ if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) {
+ /* if it's an index, get the index */
+ returnCode = TPM_Load32(&d1DelegateIndex, &stream, &stream_size);
+ }
+ else {
+ /* if it's a blob, get the blob structure tag to determine the blob type */
+ returnCode = TPM_Load16(&d1Tag, &stream, &stream_size);
+ }
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* use a temporary copy so the original values are not moved */
+ stream = inputData.buffer;
+ stream_size = inputData.size;
+ /* if inputData is a table index */
+ if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) {
+ /* a. Mapping to TPM_DELEGATE_TABLE_ROW requires taking inputData as a tableIndex and
+ locating the appropriate row in the table */
+ returnCode =
+ TPM_DelegateTable_GetValidRow(&d1DelegateTableRow,
+ &(tpm_state->tpm_permanent_data.delegateTable),
+ d1DelegateIndex);
+ familyID = d1DelegateTableRow->pub.familyID;
+ }
+ /* if inputData is a blob */
+ else {
+ switch (d1Tag) {
+ case TPM_TAG_DELEGATE_OWNER_BLOB:
+ returnCode = TPM_DelegateOwnerBlob_Load(&d1DelegateOwnerBlob,
+ &stream, &stream_size);
+ familyID = d1DelegateOwnerBlob.pub.familyID;
+ break;
+ case TPM_TAG_DELG_KEY_BLOB:
+ returnCode = TPM_DelegateKeyBlob_Load(&d1DelegateKeyBlob,
+ &stream, &stream_size);
+ familyID = d1DelegateKeyBlob.pub.familyID;
+ break;
+ default:
+ printf("TPM_Process_DelegateUpdateVerification: Error, invalid tag %04hx\n", d1Tag);
+ returnCode = TPM_BAD_PARAMETER;
+ break;
+ }
+ }
+ }
+ /* 3. If D1 is TPM_DELEGATE_OWNER_BLOB or TPM_DELEGATE_KEY_BLOB Validate the integrity of
+ D1 */
+ if ((returnCode == TPM_SUCCESS) && (inputData.size != sizeof(TPM_DELEGATE_INDEX))) {
+ /* a. Copy D1 -> integrityDigest to H2 */
+ /* b. Set D1 -> integrityDigest to NULL */
+ /* c. Create H3 the HMAC of D1 using tpmProof as the secret */
+ /* d. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */
+ switch (d1Tag) {
+ case TPM_TAG_DELEGATE_OWNER_BLOB:
+ returnCode = TPM_HMAC_CheckStructure
+ (tpm_state->tpm_permanent_data.tpmProof, /* key */
+ &d1DelegateOwnerBlob, /* structure */
+ d1DelegateOwnerBlob.integrityDigest, /* expected */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store, /* store function */
+ TPM_AUTHFAIL); /* error code */
+ break;
+ case TPM_TAG_DELG_KEY_BLOB:
+ returnCode = TPM_HMAC_CheckStructure
+ (tpm_state->tpm_permanent_data.tpmProof, /* key */
+ &d1DelegateKeyBlob, /* structure */
+ d1DelegateKeyBlob.integrityDigest, /* expected */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store, /* store function */
+ TPM_AUTHFAIL); /* error code */
+ break;
+ /* default error tested above */
+ }
+ }
+ /* 4. Locate (D1 -> pub -> familyID) in the TPM_FAMILY_TABLE and set familyRow to indicate row,
+ return TPM_BADINDEX if not found */
+ /* 5. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_FamilyTable_GetEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ familyID);
+ }
+ if ((returnCode == TPM_SUCCESS) && (auth_session_data->protocolID == TPM_PID_DSAP)) {
+ /* get the TPM_DELEGATE_PUBLIC from the DSAP session */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic,
+ auth_session_data);
+ }
+ /* 6. If delegated, verify that family of the delegated Owner-auth is the same as D1:
+ (authHandle -> familyID) == (D1 -> pub -> familyID); otherwise return error
+ TPM_DELEGATE_FAMILY */
+ if (returnCode == TPM_SUCCESS) {
+ if (familyID != delegatePublic->familyID) {
+ printf("TPM_Process_DelegateUpdateVerification: Error, "
+ "familyID %u should be %u\n",
+ familyID, delegatePublic->familyID);
+ returnCode = TPM_DELEGATE_FAMILY;
+ }
+ }
+ /* 7. If delegated, verify that the family of the delegated Owner-auth is enabled: if
+ (authHandle -> familyID -> flags TPM_FAMFLAG_ENABLED) is FALSE, return
+ TPM_DISABLED_CMD */
+ if (returnCode == TPM_SUCCESS) {
+ if (!(familyRow->flags & TPM_FAMFLAG_ENABLED)) {
+ printf("TPM_Process_DelegateUpdateVerification: Error, family %u disabled\n",
+ familyID);
+ returnCode = TPM_DISABLED_CMD;
+ }
+ }
+ }
+ /* 8. Set D1 -> verificationCount to FR -> verificationCount */
+ if (returnCode == TPM_SUCCESS) {
+ if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) {
+ d1DelegateTableRow->pub.verificationCount = familyRow->verificationCount;
+ writeAllNV = TRUE;
+ }
+ else {
+ switch (d1Tag) {
+ case TPM_TAG_DELEGATE_OWNER_BLOB:
+ d1DelegateOwnerBlob.pub.verificationCount = familyRow->verificationCount;
+ break;
+ case TPM_TAG_DELG_KEY_BLOB:
+ d1DelegateKeyBlob.pub.verificationCount = familyRow->verificationCount;
+ break;
+ /* default error tested above */
+ }
+ }
+ }
+ /* 9. If D1 is TPM_DELEGATE_OWNER_BLOB or TPM_DELEGATE_KEY_BLOB set the integrity of D1 */
+ if ((returnCode == TPM_SUCCESS) && (inputData.size != sizeof(TPM_DELEGATE_INDEX))) {
+ /* a. Set D1 -> integrityDigest to NULL */
+ /* NOTE Done by TPM_HMAC_GenerateStructure() */
+ /* b. Create H1 the HMAC of D1 using tpmProof as the secret */
+ /* c. Set D1 -> integrityDigest to H1 */
+ /* NOTE It is safe to HMAC directly into the blob, since the structure is serialized before
+ the HMAC is performed */
+ switch (d1Tag) {
+ case TPM_TAG_DELEGATE_OWNER_BLOB:
+ returnCode = TPM_HMAC_GenerateStructure
+ (d1DelegateOwnerBlob.integrityDigest, /* HMAC */
+ tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */
+ &d1DelegateOwnerBlob, /* structure */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store); /* store function */
+ break;
+ case TPM_TAG_DELG_KEY_BLOB:
+ returnCode = TPM_HMAC_GenerateStructure
+ (d1DelegateKeyBlob.integrityDigest, /* HMAC */
+ tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */
+ &d1DelegateKeyBlob, /* structure */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store); /* store function */
+ break;
+ }
+ }
+ /* If updating a delegate row, write back TPM_PERMANENT_DATA */
+ if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) {
+ returnCode = TPM_PermanentAll_NVStore(tpm_state,
+ writeAllNV,
+ returnCode);
+ }
+ /* 10. If D1 is a blob recreate the blob and return it */
+ else {
+ if (returnCode == TPM_SUCCESS) {
+ switch (d1Tag) {
+ case TPM_TAG_DELEGATE_OWNER_BLOB:
+ returnCode = TPM_DelegateOwnerBlob_Store(&outputDataSbuffer,
+ &d1DelegateOwnerBlob);
+ break;
+ case TPM_TAG_DELG_KEY_BLOB:
+ returnCode = TPM_DelegateKeyBlob_Store(&outputDataSbuffer,
+ &d1DelegateKeyBlob);
+ break;
+ /* default error tested above */
+ }
+ }
+ }
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_DelegateUpdateVerification: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* return outputSize and outputData */
+ returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &outputDataSbuffer);
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* calculate and set the below the line parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_AuthParams_Set(response,
+ *hmacKey, /* HMAC key */
+ auth_session_data,
+ outParamDigest,
+ nonceOdd,
+ continueAuthSession);
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /* if there was an error, or continueAuthSession is FALSE, terminate the session */
+ if (((rcf != 0) ||
+ ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) ||
+ !continueAuthSession) &&
+ authHandleValid) {
+ TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle);
+ }
+ /*
+ cleanup
+ */
+ TPM_SizedBuffer_Delete(&inputData); /* @1 */
+ TPM_DelegateOwnerBlob_Delete(&d1DelegateOwnerBlob); /* @2 */
+ TPM_DelegateKeyBlob_Delete(&d1DelegateKeyBlob); /* @3 */
+ TPM_Sbuffer_Delete(&outputDataSbuffer); /* @4 */
+ return rcf;
+}
+
+/* 19.7 TPM_Delegate_VerifyDelegation rev 105
+
+ VerifyDelegation interprets a delegate blob and returns success or failure, depending on whether
+ the blob is currently valid. The delegate blob is NOT loaded into the TPM.
+*/
+
+TPM_RESULT TPM_Process_DelegateVerifyDelegation(tpm_state_t *tpm_state,
+ TPM_STORE_BUFFER *response,
+ TPM_TAG tag,
+ uint32_t paramSize,
+ TPM_COMMAND_CODE ordinal,
+ unsigned char *command,
+ TPM_TRANSPORT_INTERNAL *transportInternal)
+{
+ TPM_RESULT rcf = 0; /* fatal error precluding response */
+ TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */
+
+ /* input parameters */
+ TPM_SIZED_BUFFER delegation; /* TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB */
+
+ /* processing parameters */
+ unsigned char * inParamStart; /* starting point of inParam's */
+ unsigned char * inParamEnd; /* ending point of inParam's */
+ TPM_DIGEST inParamDigest;
+ TPM_BOOL auditStatus; /* audit the ordinal */
+ TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */
+ unsigned char *stream; /* temp input stream */
+ uint32_t stream_size;
+ TPM_STRUCTURE_TAG d1Tag; /* input structure tag */
+ TPM_DELEGATE_OWNER_BLOB d1DelegateOwnerBlob;
+ TPM_DELEGATE_KEY_BLOB d1DelegateKeyBlob;
+ TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */
+ TPM_FAMILY_ID familyID;
+ TPM_FAMILY_VERIFICATION verificationCount = 0;
+ TPM_DELEGATE_SENSITIVE s1DelegateSensitive;
+
+ /* output parameters */
+ uint32_t outParamStart; /* starting point of outParam's */
+ uint32_t outParamEnd; /* ending point of outParam's */
+ TPM_DIGEST outParamDigest;
+
+ printf("TPM_Process_DelegateVerifyDelegation: Ordinal Entry\n");
+ TPM_SizedBuffer_Init(&delegation); /* freed @1 */
+ TPM_DelegateOwnerBlob_Init(&d1DelegateOwnerBlob); /* freed @2 */
+ TPM_DelegateKeyBlob_Init(&d1DelegateKeyBlob); /* freed @3 */
+ TPM_DelegateSensitive_Init(&s1DelegateSensitive); /* freed @4 */
+ /*
+ get inputs
+ */
+ /* save the starting point of inParam's for authorization and auditing */
+ inParamStart = command;
+ /* get delegation parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_SizedBuffer_Load(&delegation, &command, &paramSize);
+ }
+ /* save the ending point of inParam's for authorization and auditing */
+ inParamEnd = command;
+ /* digest the input parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetInParamDigest(inParamDigest, /* output */
+ &auditStatus, /* output */
+ &transportEncrypt, /* output */
+ tpm_state,
+ tag,
+ ordinal,
+ inParamStart,
+ inParamEnd,
+ transportInternal);
+ }
+ /* check state */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL);
+ }
+ /* check tag */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_CheckRequestTag0(tag);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ if (paramSize != 0) {
+ printf("TPM_Process_DelegateVerifyDelegation: Error, command has %u extra bytes\n",
+ paramSize);
+ returnCode = TPM_BAD_PARAM_SIZE;
+ }
+ }
+ /*
+ Processing
+ */
+ /* 1. Determine the type of blob */
+ if (returnCode == TPM_SUCCESS) {
+ /* use a temporary copy so the original values are not moved */
+ stream = delegation.buffer;
+ stream_size = delegation.size;
+ returnCode = TPM_Load16(&d1Tag, &stream, &stream_size);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ /* use a temporary copy so the original values are not moved */
+ stream = delegation.buffer;
+ stream_size = delegation.size;
+ switch (d1Tag) {
+ /* 1. If delegation -> tag is equal to TPM_TAG_DELEGATE_OWNER_BLOB then */
+ case TPM_TAG_DELEGATE_OWNER_BLOB:
+ /* a. Map D1 a TPM_DELEGATE_BLOB_OWNER to delegation */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateOwnerBlob_Load(&d1DelegateOwnerBlob,
+ &stream, &stream_size);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ familyID = d1DelegateOwnerBlob.pub.familyID;
+ verificationCount = d1DelegateOwnerBlob.pub.verificationCount;
+ }
+ break;
+ /* 2. Else if delegation -> tag = TPM_TAG_DELG_KEY_BLOB */
+ case TPM_TAG_DELG_KEY_BLOB:
+ /* a. Map D1 a TPM_DELEGATE_KEY_BLOB to delegation */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_DelegateKeyBlob_Load(&d1DelegateKeyBlob, &stream, &stream_size);
+ }
+ if (returnCode == TPM_SUCCESS) {
+ familyID = d1DelegateKeyBlob.pub.familyID;
+ verificationCount = d1DelegateKeyBlob.pub.verificationCount;
+ }
+ break;
+ /* 3. Else return TPM_BAD_PARAMETER */
+ default:
+ printf("TPM_Process_DelegateVerifyDelegation: Error, invalid tag %04hx\n", d1Tag);
+ returnCode = TPM_BAD_PARAMETER;
+ break;
+ }
+ }
+ /* 4. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row, return
+ TPM_BADINDEX if not found */
+ /* 5. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */
+ /* 6. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_FamilyTable_GetEnabledEntry(&familyRow,
+ &(tpm_state->tpm_permanent_data.familyTable),
+ familyID);
+ }
+ /* 7. Validate that D1 -> pub -> verificationCount matches FR -> verificationCount, on mismatch
+ return TPM_FAMILYCOUNT */
+ if (returnCode == TPM_SUCCESS) {
+ if (verificationCount != familyRow->verificationCount) {
+ printf("TPM_Process_DelegateVerifyDelegation: Error, "
+ "verificationCount mismatch %u %u\n",
+ verificationCount, familyRow->verificationCount);
+ returnCode = TPM_FAMILYCOUNT;
+ }
+ }
+ /* 8. Validate the integrity of D1 */
+ /* a. Copy D1 -> integrityDigest to H2 */
+ /* b. Set D1 -> integrityDigest to NULL */
+ /* c. Create H3 the HMAC of D1 using tpmProof as the secret */
+ /* d. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */
+ if (returnCode == TPM_SUCCESS) {
+ if (d1Tag == TPM_TAG_DELEGATE_OWNER_BLOB) {
+ returnCode = TPM_HMAC_CheckStructure
+ (tpm_state->tpm_permanent_data.tpmProof, /* key */
+ &d1DelegateOwnerBlob, /* structure */
+ d1DelegateOwnerBlob.integrityDigest, /* expected */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store, /* store function */
+ TPM_AUTHFAIL); /* error code */
+ }
+ else {
+ returnCode = TPM_HMAC_CheckStructure
+ (tpm_state->tpm_permanent_data.tpmProof, /* key */
+ &d1DelegateKeyBlob, /* structure */
+ d1DelegateKeyBlob.integrityDigest, /* expected */
+ (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store, /* store function */
+ TPM_AUTHFAIL); /* error code */
+ }
+ }
+ /* 9. Create S1 a TPM_DELEGATE_SENSITIVE area by decrypting D1 -> sensitiveArea using
+ TPM_DELEGATE_KEY */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_DelegateVerifyDelegation: Decrypting sensitiveArea\n");
+ if (d1Tag == TPM_TAG_DELEGATE_OWNER_BLOB) {
+ returnCode =
+ TPM_DelegateSensitive_DecryptEncData(&s1DelegateSensitive,
+ &(d1DelegateOwnerBlob.sensitiveArea),
+ tpm_state->tpm_permanent_data.delegateKey);
+ }
+ else {
+ returnCode =
+ TPM_DelegateSensitive_DecryptEncData(&s1DelegateSensitive,
+ &(d1DelegateKeyBlob.sensitiveArea),
+ tpm_state->tpm_permanent_data.delegateKey);
+ }
+ }
+ /* 10. Validate S1 values */
+ /* a. S1 -> tag is TPM_TAG_DELEGATE_SENSITIVE */
+ /* NOTE Done by TPM_DelegateSensitive_DecryptEncData() */
+ /* b. Return TPM_BAD_PARAMETER on error */
+ /* 11. Return TPM_SUCCESS */
+ /*
+ response
+ */
+ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */
+ if (rcf == 0) {
+ printf("TPM_Process_DelegateVerifyDelegation: Ordinal returnCode %08x %u\n",
+ returnCode, returnCode);
+ rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode);
+ }
+ /* success response, append the rest of the parameters. */
+ if (rcf == 0) {
+ if (returnCode == TPM_SUCCESS) {
+ /* checkpoint the beginning of the outParam's */
+ outParamStart = response->buffer_current - response->buffer;
+ /* checkpoint the end of the outParam's */
+ outParamEnd = response->buffer_current - response->buffer;
+ }
+ /* digest the above the line output parameters */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */
+ auditStatus, /* input audit status */
+ transportEncrypt,
+ tag,
+ returnCode,
+ ordinal, /* command ordinal */
+ response->buffer + outParamStart, /* start */
+ outParamEnd - outParamStart); /* length */
+ }
+ /* audit if required */
+ if ((returnCode == TPM_SUCCESS) && auditStatus) {
+ returnCode = TPM_ProcessAudit(tpm_state,
+ transportEncrypt,
+ inParamDigest,
+ outParamDigest,
+ ordinal);
+ }
+ /* adjust the initial response */
+ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state);
+ }
+ /*
+ cleanup
+ */
+ TPM_SizedBuffer_Delete(&delegation); /* @1 */
+ TPM_DelegateOwnerBlob_Delete(&d1DelegateOwnerBlob); /* @2 */
+ TPM_DelegateKeyBlob_Delete(&d1DelegateKeyBlob); /* @3 */
+ TPM_DelegateSensitive_Delete(&s1DelegateSensitive); /* @4 */
+ return rcf;
+}