diff options
Diffstat (limited to 'src/tpm12/tpm_delegate.c')
-rw-r--r-- | src/tpm12/tpm_delegate.c | 3944 |
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, ¶mSize); + } + /* get opCode parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: familyID %08x\n", familyID); + returnCode = TPM_Load32(&opCode, &command, ¶mSize); + } + /* get opData parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: opCode %u\n", opCode); + returnCode = TPM_SizedBuffer_Load(&opData, &command, ¶mSize); + } + /* 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, ¶mSize); + } + 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, ¶mSize); + } + /* 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, ¶mSize); + } + /* get delAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(delAuth, &command, ¶mSize); + } + /* 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, ¶mSize); + } + 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, ¶mSize); + } + /* get publicInfo parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: increment %02x\n", increment); + returnCode = TPM_DelegatePublic_Load(&publicInfo, &command, ¶mSize); + } + /* get delAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(delAuth, &command, ¶mSize); + } + /* 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, ¶mSize); + } + 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, ¶mSize); + } + /* get blobSize parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateLoadOwnerDelegation: index %u\n", index); + returnCode = TPM_Load32(&blobSize, &command, ¶mSize); + } + /* get blob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateOwnerBlob_Load(&d1Blob, &command, ¶mSize); + } + /* 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, ¶mSize); + } + 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, ¶mSize); + } + /* 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, ¶mSize); + } + 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, ¶mSize); + } + /* 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; +} |