/********************************************************************************/ /* */ /* Transport */ /* Written by Ken Goldman */ /* IBM Thomas J. Watson Research Center */ /* $Id: tpm_transport.c 4719 2014-01-15 21:17:47Z 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 #include #include #include "tpm_audit.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_init.h" #include "tpm_key.h" #include "tpm_memory.h" #include "tpm_nonce.h" #include "tpm_process.h" #include "tpm_secret.h" #include "tpm_ticks.h" #include "tpm_transport.h" /* TPM_Transport_CryptMgf1() takes a 'src', a preallocated 'dest', and an MGF1 'pad' of length 'len'. 'size is the total length of 'src' and 'dest'. 'index' is the start of the encrypt area 'len' is the length of the encrypt area It copies 'src' to 'dest' up to 'index'. It then copies 'src' XOR'ed with 'pad' for 'len' It then copies the remainder of 'src' to 'dest' */ TPM_RESULT TPM_Transport_CryptMgf1(unsigned char *dest, const unsigned char *src, const unsigned char *pad, uint32_t size, uint32_t index, uint32_t len) { TPM_RESULT rc = 0; printf(" TPM_Transport_CryptMgf1: size %u index %u len %u\n", size, index, len); /* sanity check the length */ if (rc == 0) { if (index + len > size) { printf("TPM_Transport_CryptMgf1: Error (fatal), bad size\n"); rc = TPM_FAIL; /* internal error, should never occur */ } } if (rc == 0) { /* leading clear text area */ memcpy(dest, src, index); dest += index; src += index; /* encrypt area */ TPM_XOR(dest, pad, src, len); dest += len; src += len; /* trailing clear text area */ memcpy(dest, src, size - index - len); } return rc; } /* TPM_Transport_CryptSymmetric() takes a 'src', a preallocated 'dest', and a 'symmetric_key' 'pad_in' (CTR or IV) of length 'len'. 'size is the total length of 'src' and 'dest'. 'index' is the start of the encrypt area 'len' is the length of the encrypt area It copies 'src' to 'dest' up to 'index'. It then encrypts 'src' to 'dest' using 'symmetric_key and 'pad_in' for 'len' It then copies the remainder of 'src' to 'dest' */ TPM_RESULT TPM_Transport_CryptSymmetric(unsigned char *dest, const unsigned char *src, TPM_ALGORITHM_ID algId, /* algorithm */ TPM_ENC_SCHEME encScheme, /* mode */ const unsigned char *symmetric_key, uint32_t symmetric_key_size, unsigned char *pad_in, uint32_t pad_in_size, uint32_t size, uint32_t index, uint32_t len) { TPM_RESULT rc = 0; printf(" TPM_Transport_CryptSymmetric: size %u index %u len %u\n", size, index, len); /* sanity check the length */ if (rc == 0) { if (index + len > size) { printf("TPM_Transport_CryptSymmetric: Error (fatal), bad size\n"); rc = TPM_FAIL; /* internal error, should never occur */ } } if (rc == 0) { /* leading clear text area */ memcpy(dest, src, index); dest += index; src += index; /* encrypt area */ rc = TPM_SymmetricKeyData_StreamCrypt(dest, /* output */ src, /* input */ len, /* input */ algId, /* algorithm */ encScheme, /* mode */ symmetric_key, /* input */ symmetric_key_size, /* input */ pad_in, /* input */ pad_in_size); /* input */ } if (rc == 0) { dest += len; src += len; /* trailing clear text area */ memcpy(dest, src, size - index - len); } return rc; } /* Transport Sessions (the entire array) */ void TPM_TransportSessions_Init(TPM_TRANSPORT_INTERNAL *transSessions) { size_t i; printf(" TPM_TransportSessions_Init:\n"); for (i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) { TPM_TransportInternal_Init(&(transSessions[i])); } return; } /* TPM_TransportSessions_Load() reads a count of the number of stored sessions and then loads those sessions. deserialize the structure from a 'stream' 'stream_size' is checked for sufficient data returns 0 or error codes Before use, call TPM_TransportSessions_Init() After use, call TPM_TransportSessions_Delete() to free memory */ TPM_RESULT TPM_TransportSessions_Load(TPM_TRANSPORT_INTERNAL *transSessions, unsigned char **stream, uint32_t *stream_size) { TPM_RESULT rc = 0; size_t i; uint32_t activeCount; printf(" TPM_TransportSessions_Load:\n"); /* load active count */ if (rc == 0) { rc = TPM_Load32(&activeCount, stream, stream_size); } if (rc == 0) { if (activeCount > TPM_MIN_TRANS_SESSIONS) { printf("TPM_TransportSessions_Load: Error (fatal) %u sessions, %u slots\n", activeCount, TPM_MIN_TRANS_SESSIONS); rc = TPM_FAIL; } } if (rc == 0) { printf(" TPM_TransportSessions_Load: Loading %u sessions\n", activeCount); } for (i = 0 ; (rc == 0) && (i < activeCount) ; i++) { rc = TPM_TransportInternal_Load(&(transSessions[i]), stream, stream_size); } return rc; } /* TPM_TransportSessions_Store() stores a count of the active sessions, followed by the sessions. serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes */ TPM_RESULT TPM_TransportSessions_Store(TPM_STORE_BUFFER *sbuffer, TPM_TRANSPORT_INTERNAL *transSessions) { TPM_RESULT rc = 0; size_t i; uint32_t space; /* free transport session slots */ uint32_t activeCount; /* used transport session slots */ /* store active count */ if (rc == 0) { TPM_TransportSessions_GetSpace(&space, transSessions); activeCount = TPM_MIN_TRANS_SESSIONS - space; printf(" TPM_TransSessions_Store: Storing %u sessions\n", activeCount); rc = TPM_Sbuffer_Append32(sbuffer, activeCount); } /* store transport sessions */ for (i = 0 ; (rc == 0) && (i < TPM_MIN_TRANS_SESSIONS) ; i++) { if ((transSessions[i]).valid) { /* if the session is active */ rc = TPM_TransportInternal_Store(sbuffer, &(transSessions[i])); } } return rc; } /* TPM_TransportSessions_Delete() terminates all sessions No-OP if the parameter is NULL, else: frees memory allocated for the object sets pointers to NULL calls TPM_TransportSessions_Init to set members back to default values The object itself is not freed */ void TPM_TransportSessions_Delete(TPM_TRANSPORT_INTERNAL *transSessions) { size_t i; printf(" TPM_TransportSessions_Delete:\n"); for (i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) { TPM_TransportInternal_Delete(&(transSessions[i])); } return; } /* TPM_TransportSessions_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not. If TRUE, 'index' holds the first free position. */ void TPM_TransportSessions_IsSpace(TPM_BOOL *isSpace, uint32_t *index, TPM_TRANSPORT_INTERNAL *transSessions) { printf(" TPM_TransportSessions_IsSpace:\n"); for (*index = 0, *isSpace = FALSE ; *index < TPM_MIN_TRANS_SESSIONS ; (*index)++) { if (!((transSessions[*index]).valid)) { printf(" TPM_TransportSessions_IsSpace: Found space at %u\n", *index); *isSpace = TRUE; break; } } return; } /* TPM_TransportSessions_GetSpace() returns the number of unused transport sessions. */ void TPM_TransportSessions_GetSpace(uint32_t *space, TPM_TRANSPORT_INTERNAL *transSessions) { uint32_t i; printf(" TPM_TransportSessions_GetSpace:\n"); for (*space = 0 , i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) { if (!((transSessions[i]).valid)) { (*space)++; } } return; } /* TPM_TransportSessions_StoreHandles() stores - the number of loaded sessions - a list of session handles */ TPM_RESULT TPM_TransportSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, TPM_TRANSPORT_INTERNAL *transSessions) { TPM_RESULT rc = 0; uint16_t i; uint32_t space; printf(" TPM_TransportSessions_StoreHandles:\n"); /* get the number of loaded handles */ if (rc == 0) { TPM_TransportSessions_GetSpace(&space, transSessions); /* store loaded handle count. Cast safe because of TPM_MIN_TRANS_SESSIONS value */ printf(" TPM_TransportSessions_StoreHandles: %u handles\n", TPM_MIN_TRANS_SESSIONS - space); rc = TPM_Sbuffer_Append16(sbuffer, (uint16_t)(TPM_MIN_TRANS_SESSIONS - space)); } for (i = 0 ; (rc == 0) && (i < TPM_MIN_TRANS_SESSIONS) ; i++) { if ((transSessions[i]).valid) { /* if the index is loaded */ rc = TPM_Sbuffer_Append32(sbuffer, (transSessions[i]).transHandle); /* store it */ } } return rc; } /* TPM_TransportSessions_GetNewHandle() checks for space in the transport sessions table. If there is space, it returns a TPM_TRANSPORT_INTERNAL entry in 'tpm_transport_internal'. The entry is marked 'valid'. Returns TPM_RESOURCES if there is no space in the transport sessions table. */ TPM_RESULT TPM_TransportSessions_GetNewHandle(TPM_TRANSPORT_INTERNAL **tpm_transport_internal, TPM_TRANSPORT_INTERNAL *transportSessions) { TPM_RESULT rc = 0; uint32_t index; TPM_BOOL isSpace; TPM_TRANSHANDLE transportHandle = 0; /* no suggested value */ printf(" TPM_TransportSessions_GetNewHandle:\n"); /* is there an empty entry, get the location index */ if (rc == 0) { TPM_TransportSessions_IsSpace(&isSpace, &index, transportSessions); if (!isSpace) { printf("TPM_TransportSessions_GetNewHandle: Error, " "no space in TransportSessions table\n"); rc = TPM_RESOURCES; } } /* assign transport handle */ if (rc == 0) { rc = TPM_Handle_GenerateHandle(&transportHandle, /* I/O */ transportSessions, /* handle array */ FALSE, /* keepHandle */ FALSE, /* isKeyHandle */ (TPM_GETENTRY_FUNCTION_T)TPM_TransportSessions_GetEntry); } if (rc == 0) { printf(" TPM_TransportSessions_GetNewHandle: Assigned handle %08x\n", transportHandle); /* return the TPM_TRANSPORT_INTERNAL */ *tpm_transport_internal = &(transportSessions[index]); /* assign the handle */ (*tpm_transport_internal)->transHandle = transportHandle; (*tpm_transport_internal)->valid = TRUE; } return rc; } /* TPM_TransportSessions_GetEntry() searches all 'transportSessions' entries for the entry matching the handle, and returns the TPM_TRANSPORT_INTERNAL entry associated with the handle. Returns 0 for success TPM_INVALID_AUTHHANDLE if the handle is not found */ TPM_RESULT TPM_TransportSessions_GetEntry(TPM_TRANSPORT_INTERNAL **tpm_transport_internal, TPM_TRANSPORT_INTERNAL *transportSessions, /* array */ TPM_TRANSHANDLE transportHandle) /* input */ { TPM_RESULT rc = 0; size_t i; TPM_BOOL found; printf(" TPM_TransportSessions_GetEntry: transportHandle %08x\n", transportHandle); for (i = 0, found = FALSE ; (i < TPM_MIN_TRANS_SESSIONS) && !found ; i++) { if ((transportSessions[i].valid) && (transportSessions[i].transHandle == transportHandle)) { /* found */ found = TRUE; *tpm_transport_internal = &(transportSessions[i]); } } if (!found) { printf(" TPM_TransportSessions_GetEntry: transport session handle %08x not found\n", transportHandle); rc = TPM_INVALID_AUTHHANDLE; } return rc; } /* TPM_TransportSessions_AddEntry() adds an TPM_TRANSPORT_INTERNAL object to the list. If *tpm_handle == 0, a value is assigned. If *tpm_handle != 0, that value is used if it it not currently in use. The handle is returned in tpm_handle. */ TPM_RESULT TPM_TransportSessions_AddEntry(TPM_HANDLE *tpm_handle, /* i/o */ TPM_BOOL keepHandle, /* input */ TPM_TRANSPORT_INTERNAL *transSessions, /* input */ TPM_TRANSPORT_INTERNAL *tpm_transport_internal) /* in */ { TPM_RESULT rc = 0; uint32_t index; TPM_BOOL isSpace; printf(" TPM_TransportSessions_AddEntry: handle %08x, keepHandle %u\n", *tpm_handle, keepHandle); /* check for valid TPM_TRANSPORT_INTERNAL */ if (rc == 0) { if (tpm_transport_internal == NULL) { /* NOTE: should never occur */ printf("TPM_TransportSessions_AddEntry: Error (fatal), NULL TPM_TRANSPORT_INTERNAL\n"); rc = TPM_FAIL; } } /* is there an empty entry, get the location index */ if (rc == 0) { TPM_TransportSessions_IsSpace(&isSpace, &index, transSessions); if (!isSpace) { printf("TPM_TransportSessions_AddEntry: Error, transport session entries full\n"); rc = TPM_RESOURCES; } } if (rc == 0) { rc = TPM_Handle_GenerateHandle(tpm_handle, /* I/O */ transSessions, /* handle array */ keepHandle, /* keepHandle */ FALSE, /* isKeyHandle */ (TPM_GETENTRY_FUNCTION_T)TPM_TransportSessions_GetEntry); } if (rc == 0) { tpm_transport_internal->transHandle = *tpm_handle; tpm_transport_internal->valid = TRUE; TPM_TransportInternal_Copy(&(transSessions[index]), tpm_transport_internal); printf(" TPM_TransportSessions_AddEntry: Index %u handle %08x\n", index, transSessions[index].transHandle); } return rc; } /* TPM_TransportSessions_TerminateHandle() terminates the session associated with 'transporthHandle'. If the session is exclusive (indicated by a match with TPM_STANY_FLAGS -> transportExclusive), clear that flag. */ TPM_RESULT TPM_TransportSessions_TerminateHandle(TPM_TRANSPORT_INTERNAL *transportSessions, TPM_TRANSHANDLE transportHandle, TPM_TRANSHANDLE *transportExclusive) { TPM_RESULT rc = 0; TPM_TRANSPORT_INTERNAL *tpm_transport_internal; printf(" TPM_TransportSessions_TerminateHandle: Handle %08x\n", transportHandle); /* get the TPM_TRANSPORT_INTERNAL associated with the TPM_TRANSHANDLE */ if (rc == 0) { rc = TPM_TransportSessions_GetEntry(&tpm_transport_internal, transportSessions, transportHandle); } /* if the session being terminated is exclusive, reset the flag */ if (rc == 0) { if (transportHandle == *transportExclusive) { printf(" TPM_TransportSessions_TerminateHandle: Is exclusive transport session\n"); if (!(tpm_transport_internal->transPublic.transAttributes & TPM_TRANSPORT_EXCLUSIVE)) { printf("TPM_TransportSessions_TerminateHandle: Error (fatal), " "attribute is not exclusive\n"); rc = TPM_FAIL; /* internal error, should not occur */ } *transportExclusive = 0; } } /* invalidate the valid handle */ if (rc == 0) { TPM_TransportInternal_Delete(tpm_transport_internal); } return rc; } /* TPM_TRANSPORT_PUBLIC */ /* TPM_TransportPublic_Init() sets members to default values sets all pointers to NULL and sizes to 0 always succeeds - no return code */ void TPM_TransportPublic_Init(TPM_TRANSPORT_PUBLIC *tpm_transport_public) { printf(" TPM_TransportPublic_Init:\n"); tpm_transport_public->transAttributes = 0; tpm_transport_public->algId = 0; tpm_transport_public->encScheme = TPM_ES_NONE; return; } /* TPM_TransportPublic_Load() deserialize the structure from a 'stream' 'stream_size' is checked for sufficient data returns 0 or error codes Before use, call TPM_TransportPublic_Init() After use, call TPM_TransportPublic_Delete() to free memory */ TPM_RESULT TPM_TransportPublic_Load(TPM_TRANSPORT_PUBLIC *tpm_transport_public, unsigned char **stream, uint32_t *stream_size) { TPM_RESULT rc = 0; printf(" TPM_TransportPublic_Load:\n"); /* check tag */ if (rc == 0) { rc = TPM_CheckTag(TPM_TAG_TRANSPORT_PUBLIC, stream, stream_size); } /* load transAttributes */ if (rc == 0) { rc = TPM_Load32(&(tpm_transport_public->transAttributes ), stream, stream_size); } /* load algId */ if (rc == 0) { rc = TPM_Load32(&(tpm_transport_public->algId), stream, stream_size); } /* load encScheme */ if (rc == 0) { rc = TPM_Load16(&(tpm_transport_public->encScheme), stream, stream_size); } return rc; } /* TPM_TransportPublic_Store() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes */ TPM_RESULT TPM_TransportPublic_Store(TPM_STORE_BUFFER *sbuffer, const TPM_TRANSPORT_PUBLIC *tpm_transport_public) { TPM_RESULT rc = 0; printf(" TPM_TransportPublic_Store:\n"); /* store tag */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_PUBLIC); } /* store transAttributes */ if (rc == 0) { rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_public->transAttributes); } /* store algId */ if (rc == 0) { rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_public->algId); } /* store encScheme */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, tpm_transport_public->encScheme); } return rc; } /* TPM_TransportPublic_Delete() No-OP if the parameter is NULL, else: frees memory allocated for the object sets pointers to NULL calls TPM_TransportPublic_Init to set members back to default values The object itself is not freed */ void TPM_TransportPublic_Delete(TPM_TRANSPORT_PUBLIC *tpm_transport_public) { printf(" TPM_TransportPublic_Delete:\n"); if (tpm_transport_public != NULL) { TPM_TransportPublic_Init(tpm_transport_public); } return; } /* TPM_TransportPublic_Copy() copies the 'src' to the 'dest' structure */ TPM_RESULT TPM_TransportPublic_Copy(TPM_TRANSPORT_PUBLIC *dest, const TPM_TRANSPORT_PUBLIC *src) { TPM_RESULT rc = 0; printf(" TPM_TransportPublic_Copy:\n"); /* copy transAttributes */ dest->transAttributes = src->transAttributes; /* copy algId */ dest->algId = src->algId; /* copy encScheme */ dest->encScheme = src->encScheme; return rc; } /* TPM_TransportPublic_CheckAlgId() returns 'supported' TRUE if the transport encryption algorithm is supported by the TPM */ void TPM_TransportPublic_CheckAlgId(TPM_BOOL *supported, TPM_ALGORITHM_ID algId) { printf(" TPM_TransportPublic_CheckAlgId: %08x\n", algId); switch (algId) { /* supported protocols */ case TPM_ALG_MGF1: case TPM_ALG_AES128: *supported = TRUE; break; /* unsupported protocols */ case TPM_ALG_RSA: case TPM_ALG_SHA: case TPM_ALG_HMAC: case TPM_ALG_AES192: case TPM_ALG_AES256: default: *supported = FALSE; break; } return; } /* TPM_TransportPublic_CheckEncScheme() returns success and the blockSize if the transport algId and encScheme are supported by the TPM. */ TPM_RESULT TPM_TransportPublic_CheckEncScheme(uint32_t *blockSize, TPM_ALGORITHM_ID algId, TPM_ENC_SCHEME encScheme, TPM_BOOL FIPS) { TPM_RESULT rc = 0; printf(" TPM_TransportPublic_CheckEncScheme: algId %08x encScheme %04hx\n", algId, encScheme); switch (algId) { /* supported protocols with no encScheme */ case TPM_ALG_MGF1: *blockSize = 0; /* MGF1 does not use blocks */ if (FIPS) { printf("TPM_TransportPublic_CheckEncScheme: Error, " "TPM_ALG_MGF1 not supported in FIPS\n"); rc = TPM_INAPPROPRIATE_ENC; } /* For TPM_ALG_MGF1, TPM_ENC_SCHEME is not used. The TPM MAY validate that TPM_ENC_SCHEME is TPM_ES_NONE. */ if (encScheme != TPM_ES_NONE) { printf("TPM_TransportPublic_CheckEncScheme: Error, " "TPM_ALG_MGF1 must use TPM_ES_NONE\n"); rc = TPM_INAPPROPRIATE_ENC; } break; /* protocols with encScheme */ case TPM_ALG_AES128: switch(encScheme) { case TPM_ES_SYM_CTR: /* CTR mode */ case TPM_ES_SYM_OFB: /* OFB mode */ *blockSize = 128/8; break; default: printf("TPM_TransportPublic_CheckEncScheme: Error, AES128 encScheme not supported\n"); rc = TPM_INAPPROPRIATE_ENC; break; } break; /* unsupported protocols */ case TPM_ALG_AES192: case TPM_ALG_AES256: case TPM_ALG_RSA: case TPM_ALG_SHA: case TPM_ALG_HMAC: case TPM_ALG_XOR: default: printf("TPM_TransportPublic_CheckEncScheme: Error, algId not supported\n"); rc = TPM_BAD_KEY_PROPERTY; break; } return rc; } /* TPM_TRANSPORT_INTERNAL */ /* TPM_TransportInternal_Init() sets members to default values sets all pointers to NULL and sizes to 0 always succeeds - no return code */ void TPM_TransportInternal_Init(TPM_TRANSPORT_INTERNAL *tpm_transport_internal) { printf(" TPM_TransportInternal_Init:\n"); TPM_Secret_Init(tpm_transport_internal->authData); TPM_TransportPublic_Init(&(tpm_transport_internal->transPublic)); tpm_transport_internal->transHandle = 0; TPM_Nonce_Init(tpm_transport_internal->transNonceEven); TPM_Digest_Init(tpm_transport_internal->transDigest); tpm_transport_internal->valid = FALSE; return; } /* TPM_TransportInternal_Load() deserialize the structure from a 'stream' 'stream_size' is checked for sufficient data returns 0 or error codes Before use, call TPM_TransportInternal_Init() After use, call TPM_TransportInternal_Delete() to free memory */ TPM_RESULT TPM_TransportInternal_Load(TPM_TRANSPORT_INTERNAL *tpm_transport_internal, unsigned char **stream, uint32_t *stream_size) { TPM_RESULT rc = 0; printf(" TPM_TransportInternal_Load:\n"); /* check tag */ if (rc == 0) { rc = TPM_CheckTag(TPM_TAG_TRANSPORT_INTERNAL, stream, stream_size); } /* load authData */ if (rc == 0) { rc = TPM_Secret_Load(tpm_transport_internal->authData, stream, stream_size); } /* load transPublic */ if (rc == 0) { rc = TPM_TransportPublic_Load(&(tpm_transport_internal->transPublic), stream, stream_size); } /* load transHandle */ if (rc == 0) { rc = TPM_Load32(&(tpm_transport_internal->transHandle), stream, stream_size); } /* load transNonceEven */ if (rc == 0) { rc = TPM_Nonce_Load(tpm_transport_internal->transNonceEven, stream, stream_size); } /* load transDigest */ if (rc == 0) { rc = TPM_Digest_Load(tpm_transport_internal->transDigest, stream, stream_size); } /* load valid */ if (rc == 0) { tpm_transport_internal->valid = TRUE; } return rc; } /* TPM_TransportInternal_Store() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes */ TPM_RESULT TPM_TransportInternal_Store(TPM_STORE_BUFFER *sbuffer, const TPM_TRANSPORT_INTERNAL *tpm_transport_internal) { TPM_RESULT rc = 0; printf(" TPM_TransportInternal_Store:\n"); /* store tag */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_INTERNAL); } /* store authData */ if (rc == 0) { rc = TPM_Secret_Store(sbuffer, tpm_transport_internal->authData); } /* store transPublic */ if (rc == 0) { rc = TPM_TransportPublic_Store(sbuffer, &(tpm_transport_internal->transPublic)); } /* store transHandle */ if (rc == 0) { rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_internal->transHandle); } /* store transNonceEven */ if (rc == 0) { rc = TPM_Nonce_Store(sbuffer, tpm_transport_internal->transNonceEven); } /* store transDigest */ if (rc == 0) { rc = TPM_Digest_Store(sbuffer, tpm_transport_internal->transDigest); } return rc; } /* TPM_TransportInternal_Delete() No-OP if the parameter is NULL, else: frees memory allocated for the object sets pointers to NULL calls TPM_TransportInternal_Init to set members back to default values The object itself is not freed */ void TPM_TransportInternal_Delete(TPM_TRANSPORT_INTERNAL *tpm_transport_internal) { printf(" TPM_TransportInternal_Delete:\n"); if (tpm_transport_internal != NULL) { TPM_TransportPublic_Delete(&(tpm_transport_internal->transPublic)); TPM_TransportInternal_Init(tpm_transport_internal); } return; } /* TPM_TransportInternal_Copy() copies the source to the destination. */ void TPM_TransportInternal_Copy(TPM_TRANSPORT_INTERNAL *dest_transport_internal, TPM_TRANSPORT_INTERNAL *src_transport_internal) { TPM_Secret_Copy(dest_transport_internal->authData, src_transport_internal->authData); TPM_TransportPublic_Copy(&(dest_transport_internal->transPublic), &(src_transport_internal->transPublic)); dest_transport_internal->transHandle = src_transport_internal->transHandle; TPM_Nonce_Copy(dest_transport_internal->transNonceEven, src_transport_internal->transNonceEven); TPM_Digest_Copy(dest_transport_internal->transDigest, src_transport_internal->transDigest); dest_transport_internal->valid = src_transport_internal->valid; } /* TPM_TransportInternal_Check() checks the authorization of a command. There is no need to protect against dictionary attacks. The first failure terminates the transport session. Returns TPM_AUTH2FAIL if the TPM_AUTHDATA does not match. */ TPM_RESULT TPM_TransportInternal_Check(TPM_DIGEST inParamDigest, /* digest of inputs above line */ TPM_TRANSPORT_INTERNAL *tpm_transport_internal, TPM_NONCE transNonceOdd, /* Nonce generated by system associated with transHandle */ TPM_BOOL continueTransSession, TPM_AUTHDATA transAuth) /* Authorization digest for input */ { TPM_RESULT rc = 0; TPM_BOOL valid; printf(" TPM_TransportInternal_Check:\n"); if (rc == 0) { TPM_PrintFour(" TPM_TransportInternal_Check: inParamDigest", inParamDigest); TPM_PrintFour(" TPM_TransportInternal_Check: usageAuth (key)", tpm_transport_internal->authData); TPM_PrintFour(" TPM_TransportInternal_Check: nonceEven", tpm_transport_internal->transNonceEven); TPM_PrintFour(" TPM_TransportInternal_Check: nonceOdd", transNonceOdd); printf (" TPM_TransportInternal_Check: continueSession %02x\n", continueTransSession); /* HMAC the inParamDigest, transLastNonceEven, transNonceOdd, continueTransSession */ /* transLastNonceEven is retrieved from internal transport session storage */ rc = TPM_HMAC_Check(&valid, transAuth, /* expected, from command */ tpm_transport_internal->authData, /* key */ sizeof(TPM_DIGEST), inParamDigest, /* command digest */ sizeof(TPM_NONCE), tpm_transport_internal->transNonceEven, /* 2H */ sizeof(TPM_NONCE), transNonceOdd, /* 3H */ sizeof(TPM_BOOL), &continueTransSession, /* 4H */ 0, NULL); } if (rc == 0) { if (!valid) { printf("TPM_TransportInternal_Check: Error, authorization failed\n"); rc = TPM_AUTH2FAIL; } } return rc; } /* TPM_TransportInternal_Set() sets the transport response transAuth. It conditionally generates the next transNonceEven. It appends transNonceEven and continueTransSession to the response. It generates transAuth using outParamDigest and the standard 'below the line' HMAC rules and appends it to the response. */ TPM_RESULT TPM_TransportInternal_Set(TPM_STORE_BUFFER *response, TPM_TRANSPORT_INTERNAL *tpm_transport_internal, TPM_DIGEST outParamDigest, TPM_NONCE transNonceOdd, TPM_BOOL continueTransSession, TPM_BOOL generateNonceEven) { TPM_RESULT rc = 0; TPM_AUTHDATA transAuth; /* The authorization digest for the returned parameters */ printf(" TPM_TransportInternal_Set:\n"); /* generate transNonceEven if not already done by caller */ if ((rc == 0) && generateNonceEven) { rc = TPM_Nonce_Generate(tpm_transport_internal->transNonceEven); } /* append transNonceEven */ if (rc == 0) { rc = TPM_Nonce_Store(response, tpm_transport_internal->transNonceEven); } /* append continueTransSession*/ if (rc == 0) { rc = TPM_Sbuffer_Append(response, &continueTransSession, sizeof(TPM_BOOL)); } /* Calculate transAuth using the transport session authData */ if (rc == 0) { rc = TPM_Authdata_Generate(transAuth, /* result */ tpm_transport_internal->authData, /* HMAC key */ outParamDigest, /* params */ tpm_transport_internal->transNonceEven, transNonceOdd, continueTransSession); } /* append transAuth */ if (rc == 0) { rc = TPM_Authdata_Store(response, transAuth); } return rc; } /* TPM_TRANSPORT_LOG_IN */ /* TPM_TransportLogIn_Init() sets members to default values sets all pointers to NULL and sizes to 0 always succeeds - no return code */ void TPM_TransportLogIn_Init(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) { printf(" TPM_TransportLogIn_Init:\n"); TPM_Digest_Init(tpm_transport_log_in->parameters); TPM_Digest_Init(tpm_transport_log_in->pubKeyHash); return; } /* TPM_TransportLogIn_Store() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes */ TPM_RESULT TPM_TransportLogIn_Store(TPM_STORE_BUFFER *sbuffer, const TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) { TPM_RESULT rc = 0; printf(" TPM_TransportLogIn_Store:\n"); /* store tag */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_LOG_IN); } /* store parameters */ if (rc == 0) { rc = TPM_Digest_Store(sbuffer, tpm_transport_log_in->parameters); } /* store pubKeyHash */ if (rc == 0) { rc = TPM_Digest_Store(sbuffer, tpm_transport_log_in->pubKeyHash); } return rc; } /* TPM_TransportLogIn_Delete() No-OP if the parameter is NULL, else: frees memory allocated for the object sets pointers to NULL calls TPM_TransportLogIn_Init to set members back to default values The object itself is not freed */ void TPM_TransportLogIn_Delete(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) { printf(" TPM_TransportLogIn_Delete:\n"); if (tpm_transport_log_in != NULL) { TPM_TransportLogIn_Init(tpm_transport_log_in); } return; } /* TPM_TransportLogIn_Extend() extends 'tpm_digest' tpm_digest = SHA-1 (tpm_digest || tpm_transport_log_in) */ TPM_RESULT TPM_TransportLogIn_Extend(TPM_DIGEST tpm_digest, TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) { TPM_RESULT rc = 0; TPM_STORE_BUFFER sbuffer; const unsigned char *buffer; /* serialized buffer */ uint32_t length; /* serialization length */ printf(" TPM_TransportLogIn_Extend:\n"); TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ /* serialize TPM_TRANSPORT_LOG_IN */ if (rc == 0) { rc = TPM_TransportLogIn_Store(&sbuffer, tpm_transport_log_in); } if (rc == 0) { /* get the TPM_TRANSPORT_LOG_IN serialization results */ TPM_Sbuffer_Get(&sbuffer, &buffer, &length); TPM_PrintAll(" TPM_TransportLogIn_Extend: transDigest in", tpm_digest, TPM_DIGEST_SIZE); TPM_PrintAll(" TPM_TransportLogIn_Extend", buffer, length); rc = TPM_SHA1(tpm_digest, TPM_DIGEST_SIZE, tpm_digest, length, buffer, 0, NULL); TPM_PrintAll(" TPM_TransportLogIn_Extend: transDigest out", tpm_digest, TPM_DIGEST_SIZE); } TPM_Sbuffer_Delete(&sbuffer); /* @1 */ return rc; } /* TPM_TRANSPORT_LOG_OUT */ /* TPM_TransportLogOut_Init() sets members to default values sets all pointers to NULL and sizes to 0 always succeeds - no return code */ void TPM_TransportLogOut_Init(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) { printf(" TPM_TransportLogOut_Init:\n"); TPM_CurrentTicks_Init(&(tpm_transport_log_out->currentTicks)); TPM_Digest_Init(tpm_transport_log_out->parameters); tpm_transport_log_out = 0; return; } /* TPM_TransportLogOut_Store() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes */ TPM_RESULT TPM_TransportLogOut_Store(TPM_STORE_BUFFER *sbuffer, const TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) { TPM_RESULT rc = 0; printf(" TPM_TransportLogOut_Store:\n"); /* store tag */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_LOG_OUT); } /* store currentTicks */ if (rc == 0) { rc = TPM_CurrentTicks_Store(sbuffer, &(tpm_transport_log_out->currentTicks)); } /* store parameters */ if (rc == 0) { rc = TPM_Digest_Store(sbuffer, tpm_transport_log_out->parameters); } /* store locality */ if (rc == 0) { rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_log_out->locality); } return rc; } /* TPM_TransportLogOut_Delete() No-OP if the parameter is NULL, else: frees memory allocated for the object sets pointers to NULL calls TPM_TransportLogOut_Init to set members back to default values The object itself is not freed */ void TPM_TransportLogOut_Delete(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) { printf(" TPM_TransportLogOut_Delete:\n"); if (tpm_transport_log_out != NULL) { TPM_TransportLogOut_Init(tpm_transport_log_out); } return; } /* TPM_TransportLogOut_Extend() extends 'tpm_digest' tpm_digest = SHA-1 (tpm_digest || tpm_transport_log_out) */ TPM_RESULT TPM_TransportLogOut_Extend(TPM_DIGEST tpm_digest, TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) { TPM_RESULT rc = 0; TPM_STORE_BUFFER sbuffer; const unsigned char *buffer; /* serialized buffer */ uint32_t length; /* serialization length */ printf(" TPM_TransportLogOut_Extend:\n"); TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ /* serialize TPM_TRANSPORT_LOG_OUT */ if (rc == 0) { rc = TPM_TransportLogOut_Store(&sbuffer, tpm_transport_log_out); } if (rc == 0) { /* get the TPM_TRANSPORT_LOG_OUT serialization results */ TPM_Sbuffer_Get(&sbuffer, &buffer, &length); TPM_PrintAll(" TPM_TransportLogOut_Extend: transDigest in", tpm_digest, TPM_DIGEST_SIZE); TPM_PrintAll(" TPM_TransportLogOut_Extend:", buffer, length); rc = TPM_SHA1(tpm_digest, TPM_DIGEST_SIZE, tpm_digest, length, buffer, 0, NULL); TPM_PrintAll(" TPM_TransportLogOut_Extend: transDigest out", tpm_digest, TPM_DIGEST_SIZE); } TPM_Sbuffer_Delete(&sbuffer); /* @1 */ return rc; } /* TPM_TRANSPORT_AUTH */ /* TPM_TransportAuth_Init() sets members to default values sets all pointers to NULL and sizes to 0 always succeeds - no return code */ void TPM_TransportAuth_Init(TPM_TRANSPORT_AUTH *tpm_transport_auth) { printf(" TPM_TransportAuth_Init:\n"); TPM_Secret_Init(tpm_transport_auth->authData); return; } /* TPM_TransportAuth_Load() deserialize the structure from a 'stream' 'stream_size' is checked for sufficient data returns 0 or error codes Before use, call TPM_TransportAuth_Init() After use, call TPM_TransportAuth_Delete() to free memory */ TPM_RESULT TPM_TransportAuth_Load(TPM_TRANSPORT_AUTH *tpm_transport_auth, unsigned char **stream, uint32_t *stream_size) { TPM_RESULT rc = 0; printf(" TPM_TransportAuth_Load:\n"); /* check tag */ if (rc == 0) { rc = TPM_CheckTag(TPM_TAG_TRANSPORT_AUTH, stream, stream_size); } /* load authData */ if (rc == 0) { rc = TPM_Secret_Load(tpm_transport_auth->authData, stream, stream_size); } return rc; } /* TPM_TransportAuth_Store() serialize the structure to a stream contained in 'sbuffer' returns 0 or error codes */ TPM_RESULT TPM_TransportAuth_Store(TPM_STORE_BUFFER *sbuffer, const TPM_TRANSPORT_AUTH *tpm_transport_auth) { TPM_RESULT rc = 0; printf(" TPM_TransportAuth_Store:\n"); /* store tag */ if (rc == 0) { rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_AUTH); } /* store authData */ if (rc == 0) { rc = TPM_Secret_Store(sbuffer, tpm_transport_auth->authData); } return rc; } /* TPM_TransportAuth_Delete() No-OP if the parameter is NULL, else: frees memory allocated for the object sets pointers to NULL calls TPM_TransportAuth_Init to set members back to default values The object itself is not freed */ void TPM_TransportAuth_Delete(TPM_TRANSPORT_AUTH *tpm_transport_auth) { printf(" TPM_TransportAuth_Delete:\n"); if (tpm_transport_auth != NULL) { TPM_TransportAuth_Init(tpm_transport_auth); } return; } /* TPM_TransportAuth_DecryptSecret() decrypts the secret using the private key. The result is deserialized and stored in the TPM_TRANSPORT_AUTH structure. */ TPM_RESULT TPM_TransportAuth_DecryptSecret(TPM_TRANSPORT_AUTH *tpm_transport_auth, /* result */ TPM_SIZED_BUFFER *secret, /* encrypted input */ TPM_KEY *tpm_key) /* key for decrypting */ { TPM_RESULT rc = 0; unsigned char *decryptData = NULL; /* freed @1 */ uint32_t decryptDataLength = 0; /* actual valid data */ unsigned char *stream; uint32_t stream_size; printf(" TPM_TransportAuth_DecryptSecret:\n"); /* allocate space for the decrypted data */ if (rc == 0) { rc = TPM_RSAPrivateDecryptMalloc(&decryptData, /* decrypted data */ &decryptDataLength, /* actual size of decrypted data */ secret->buffer, /* encrypted data */ secret->size, /* encrypted data size */ tpm_key); } /* load the TPM_TRANSPORT_AUTH structure from the decrypted data stream */ if (rc == 0) { /* use temporary variables, because TPM_TransportAuth_Load() moves the stream */ stream = decryptData; stream_size = decryptDataLength; rc = TPM_TransportAuth_Load(tpm_transport_auth, &stream, &stream_size); } free(decryptData); /* @1 */ return rc; } /* Processing Functions */ /* 24.1 TPM_EstablishTransport rev 98 This establishes the transport session. Depending on the attributes specified for the session this may establish shared secrets, encryption keys, and session logs. The session will be in use for by the TPM_ExecuteTransport command. The only restriction on what can happen inside of a transport session is that there is no "nesting" of sessions. It is permissible to perform operations that delete internal state and make the TPM inoperable. */ TPM_RESULT TPM_Process_EstablishTransport(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 encHandle; /* The handle to the key that encrypted the blob */ TPM_TRANSPORT_PUBLIC transPublic; /* The public information describing the transport session */ TPM_SIZED_BUFFER secret; /* The encrypted secret area */ 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; /* The continue use flag for the authorization session handle */ TPM_AUTHDATA keyAuth; /* Authorization. HMAC key: encKey.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 dataAuthHandle */ TPM_SECRET *hmacKey; TPM_KEY *encKey = NULL; /* the key specified by encHandle */ TPM_BOOL parentPCRStatus; TPM_SECRET *encKeyUsageAuth; TPM_AUTHDATA *a1AuthData = NULL; TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal; TPM_TRANSPORT_AUTH k1TransportAuth; uint32_t blockSize; /* symmetric key block size, not used */ TPM_TRANSPORT_LOG_IN l1TransportLogIn; TPM_TRANSPORT_LOG_OUT l2TransportLogOut; TPM_STORE_BUFFER transPublicSbuffer; /* serialized transPublic */ const unsigned char *transPublicBuffer; /* serialized buffer */ uint32_t transPublicLength; /* serialization length */ TPM_STORE_BUFFER currentTicksSbuffer; /* serialized currentTicks */ const unsigned char *currentTicksBuffer; /* serialized buffer */ uint32_t currentTicksLength; /* serialization length */ TPM_COMMAND_CODE nOrdinal; /* ordinal in nbo */ uint32_t nSecretSize; /* secretSize in nbo */ TPM_RESULT nReturnCode; /* returnCode in nbo */ TPM_MODIFIER_INDICATOR nLocality; /* locality in nbo */ TPM_BOOL trans_session_added = FALSE; /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_CURRENT_TICKS currentTicks; /* The current tick count */ TPM_NONCE transNonceEven; /* The even nonce in use for subsequent execute transport */ printf("TPM_Process_EstablishTransport: Ordinal Entry\n"); TPM_TransportPublic_Init(&transPublic); /* freed @1 */ TPM_SizedBuffer_Init(&secret); /* freed @2 */ TPM_CurrentTicks_Init(¤tTicks); /* no need to free */ TPM_TransportAuth_Init(&k1TransportAuth); /* freed @4 */ TPM_TransportLogIn_Init(&l1TransportLogIn); /* freed @5 */ TPM_TransportLogOut_Init(&l2TransportLogOut); /* freed @6 */ TPM_Sbuffer_Init(&transPublicSbuffer); /* freed @7 */ TPM_Sbuffer_Init(¤tTicksSbuffer); /* freed @8 */ /* get inputs */ /* get encHandle parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Load32(&encHandle, &command, ¶mSize); } /* save the starting point of inParam's for authorization and auditing */ inParamStart = command; /* get transPublic */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_EstablishTransport: keyHandle %08x\n", encHandle); returnCode = TPM_TransportPublic_Load(&transPublic, &command, ¶mSize); } /* get secret */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_EstablishTransport: transPublic->transAttributes %08x\n", transPublic.transAttributes); returnCode = TPM_SizedBuffer_Load(&secret, &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_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, keyAuth, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_EstablishTransport: 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 */ if (returnCode == TPM_SUCCESS) { /* 1. If encHandle is TPM_KH_TRANSPORT then */ if (encHandle == TPM_KH_TRANSPORT) { printf("TPM_Process_EstablishTransport: TPM_KH_TRANSPORT clear text secret\n"); /* a. If tag is NOT TPM_TAG_RQU_COMMAND return TPM_BADTAG */ if (returnCode == TPM_SUCCESS) { if (tag != TPM_TAG_RQU_COMMAND) { printf("TPM_Process_EstablishTransport: Error, " "TPM_KH_TRANSPORT but not auth-0\n"); returnCode = TPM_BADTAG; } } /* b. If transPublic -> transAttributes specifies TPM_TRANSPORT_ENCRYPT return TPM_BAD_SCHEME */ if (returnCode == TPM_SUCCESS) { if (transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) { printf("TPM_Process_EstablishTransport: Error, " "TPM_KH_TRANSPORT but TPM_TRANSPORT_ENCRYPT\n"); returnCode = TPM_BAD_SCHEME; } } /* c. If secretSize is not 20 return TPM_BAD_PARAM_SIZE */ if (returnCode == TPM_SUCCESS) { if (secret.size != TPM_DIGEST_SIZE) { printf("TPM_Process_EstablishTransport: Error, secretSize %u not %u\n", secret.size, TPM_DIGEST_SIZE); returnCode = TPM_BAD_PARAM_SIZE; } } /* d. Set A1 to secret */ if (returnCode == TPM_SUCCESS) { a1AuthData = (TPM_AUTHDATA *)(secret.buffer); TPM_PrintFour("TPM_Process_EstablishTransport: transport clear text authData", *a1AuthData); } } /* 2. Else */ else { printf("TPM_Process_EstablishTransport: Decrypt secret\n"); /* get the key corresponding to the encHandle parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_KeyHandleEntries_GetKey(&encKey, &parentPCRStatus, tpm_state, encHandle, FALSE, /* not r/o, using to encrypt */ FALSE, /* do not ignore PCRs */ FALSE); /* cannot use EK */ } /* a. encHandle -> keyUsage MUST be TPM_KEY_STORAGE or TPM_KEY_LEGACY return TPM_INVALID_KEYUSAGE on error */ if (returnCode == TPM_SUCCESS) { if ((encKey->keyUsage != TPM_KEY_STORAGE) && (encKey->keyUsage != TPM_KEY_LEGACY)) { printf("TPM_Process_EstablishTransport: Error, " "key keyUsage %04hx must be TPM_KEY_STORAGE or TPM_KEY_LEGACY\n", encKey->keyUsage); returnCode = TPM_INVALID_KEYUSAGE; } } /* b. If encHandle -> authDataUsage does not equal TPM_AUTH_NEVER and tag is NOT TPM_TAG_RQU_AUTH1_COMMAND return TPM_AUTHFAIL */ if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) { if (encKey->authDataUsage != TPM_AUTH_NEVER) { printf("TPM_Process_EstablishTransport: Error, " "encKey authorization required\n"); returnCode = TPM_AUTHFAIL; } } /* get encHandle -> usageAuth */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_Key_GetUsageAuth(&encKeyUsageAuth, encKey); } /* get the session data */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_AuthSessions_GetData(&auth_session_data, &hmacKey, tpm_state, authHandle, TPM_PID_NONE, TPM_ET_KEYHANDLE, ordinal, encKey, encKeyUsageAuth, /* OIAP */ encKey->tpm_store_asymkey-> pubDataDigest); /*OSAP */ } /* c. Using encHandle -> usageAuth, validate the AuthData to use the key and the parameters to the command */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { returnCode = TPM_Authdata_Check(tpm_state, *hmacKey, /* HMAC key */ inParamDigest, auth_session_data, /* authorization session */ nonceOdd, /* Nonce generated by system associated with authHandle */ continueAuthSession, keyAuth); /* Authorization digest for input */ } /* d. Create K1 a TPM_TRANSPORT_AUTH structure by decrypting secret using the key pointed to by encHandle */ /* e. Validate K1 for tag */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportAuth_DecryptSecret(&k1TransportAuth, &secret, encKey); } /* f. Set A1 to K1 -> authData */ if (returnCode == TPM_SUCCESS) { a1AuthData = &(k1TransportAuth.authData); TPM_PrintFour("TPM_Process_EstablishTransport: transport decrypted authData", *a1AuthData); } } } if (returnCode == TPM_SUCCESS) { TPM_PrintFour("TPM_Process_EstablishTransport: transport authData", *a1AuthData); } /* 3. If transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT */ if ((returnCode == TPM_SUCCESS) && (transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT)) { printf("TPM_Process_EstablishTransport: Check encrypt attributes\n"); /* a. If TPM_PERMANENT_FLAGS -> FIPS is true and transPublic -> algId is equal to TPM_ALG_MGF1 return TPM_INAPPROPRIATE_ENC */ /* b. Check if the transPublic -> algId is supported, if not return TPM_BAD_KEY_PROPERTY */ /* c. If transPublic -> algid is TPM_ALG_AESXXX, check that transPublic -> encScheme is supported, if not return TPM_INAPPROPRIATE_ENC */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportPublic_CheckEncScheme(&blockSize, transPublic.algId, transPublic.encScheme, tpm_state->tpm_permanent_flags.FIPS); } /* d. Perform any initializations necessary for the algorithm */ } /* 4. Generate transNonceEven from the TPM RNG */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Nonce_Generate(transNonceEven); } /* 5. Create T1 a TPM_TRANSPORT_INTERNAL structure */ /* NOTE Done by TPM_TransportInternal_Init() */ /* a. Ensure that the TPM has sufficient internal space to allocate the transport session, return TPM_RESOURCES on error */ /* b. Assign a T1 -> transHandle value. This value is assigned by the TPM */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_INTERNAL\n"); returnCode = TPM_TransportSessions_GetNewHandle(&t1TpmTransportInternal, tpm_state->tpm_stclear_data.transSessions); } if (returnCode == TPM_SUCCESS) { /* record that the entry is allocated, for invalidation on error */ trans_session_added = TRUE; /* c. Set T1 -> transDigest to NULL */ TPM_Digest_Init(t1TpmTransportInternal->transDigest); /* d. Set T1 -> transPublic to transPublic */ TPM_TransportPublic_Copy(&(t1TpmTransportInternal->transPublic), &transPublic); /* e. Set T1-> transNonceEven to transNonceEven */ TPM_Nonce_Copy(t1TpmTransportInternal->transNonceEven , transNonceEven); /* f. Set T1 -> authData to A1 */ TPM_Secret_Copy(t1TpmTransportInternal->authData, *a1AuthData); /* 6. If TPM_STANY_DATA -> currentTicks is not properly initialized */ /* a. Initialize the TPM_STANY_DATA -> currentTicks */ returnCode = TPM_CurrentTicks_Update(&(tpm_state->tpm_stany_data.currentTicks)); } /* 7. Set currentTicks to TPM_STANY_DATA -> currentTicks */ if (returnCode == TPM_SUCCESS) { TPM_CurrentTicks_Copy(¤tTicks, &(tpm_state->tpm_stany_data.currentTicks)); } /* 8. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */ if ((returnCode == TPM_SUCCESS) && (t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_LOG)) { printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_LOG_IN\n"); /* a. Create L1 a TPM_TRANSPORT_LOG_IN structure */ /* NOTE Done by TPM_TransportLogIn_Init() */ /* i. Set L1 -> parameters to SHA-1 (ordinal || transPublic || secretSize || secret) */ /* serialize transPublic */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportPublic_Store(&transPublicSbuffer, &transPublic); } if (returnCode == TPM_SUCCESS) { /* get the transPublic serialization results */ TPM_Sbuffer_Get(&transPublicSbuffer, &transPublicBuffer, &transPublicLength); /* digest the fields */ nOrdinal = htonl(ordinal); nSecretSize = htonl(secret.size); returnCode = TPM_SHA1(l1TransportLogIn.parameters, sizeof(TPM_COMMAND_CODE), &nOrdinal, transPublicLength, transPublicBuffer, sizeof(uint32_t), &nSecretSize, secret.size, secret.buffer, 0, NULL); } if (returnCode == TPM_SUCCESS) { /* ii. Set L1 -> pubKeyHash to NULL */ /* NOTE Done by TPM_TransportLogIn_Init() */ /* iii. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || L1) */ printf("TPM_Process_EstablishTransport: Extend transDigest with input\n"); returnCode = TPM_TransportLogIn_Extend(t1TpmTransportInternal->transDigest, &l1TransportLogIn); } /* b. Create L2 a TPM_TRANSPORT_LOG_OUT structure */ /* NOTE Done by TPM_TransportLogOut_Init() */ /* i. Set L2 -> parameters to SHA-1 (returnCode || ordinal || locality || currentTicks || transNonceEven) */ /* serialize currentTicks */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_LOG_OUT\n"); returnCode = TPM_CurrentTicks_Store(¤tTicksSbuffer, ¤tTicks); } if (returnCode == TPM_SUCCESS) { /* get the currentTicks serialization results */ TPM_Sbuffer_Get(¤tTicksSbuffer, ¤tTicksBuffer, ¤tTicksLength); nReturnCode = htonl(returnCode); nLocality = htonl(tpm_state->tpm_stany_flags.localityModifier); returnCode = TPM_SHA1(l2TransportLogOut.parameters, sizeof(TPM_RESULT), &nReturnCode, sizeof(TPM_COMMAND_CODE), &nOrdinal, sizeof(TPM_MODIFIER_INDICATOR), &nLocality, currentTicksLength, currentTicksBuffer, TPM_NONCE_SIZE, transNonceEven, 0, NULL); } if (returnCode == TPM_SUCCESS) { /* ii. Set L2 -> locality to the locality of this command */ l2TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier; /* iii. Set L2 -> currentTicks to currentTicks, this MUST be the same value that is returned in the currentTicks parameter */ TPM_CurrentTicks_Copy(&(l2TransportLogOut.currentTicks), ¤tTicks); /* iv. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || L2) */ printf("TPM_Process_EstablishTransport: Extend transDigest with output\n"); returnCode = TPM_TransportLogOut_Extend(t1TpmTransportInternal->transDigest, &l2TransportLogOut); } } /* 9. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_EXCLUSIVE then set TPM_STANY_FLAGS -> transportExclusive to TRUE */ if (returnCode == TPM_SUCCESS) { if (t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_EXCLUSIVE) { printf("TPM_Process_EstablishTransport: Session is exclusive\n"); tpm_state->tpm_stany_flags.transportExclusive = t1TpmTransportInternal->transHandle; } } /* a. Execution of any command other than TPM_ExecuteTransport or TPM_ReleaseTransportSigned targeting this transport session will cause the abnormal invalidation of this transport session transHandle */ /* b. The TPM gives no indication, other than invalidation of transHandle, that the session is terminated */ /* NOTE Done by TPM_Process_Preprocess() */ /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_EstablishTransport: 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) { /* 10. Return T1 -> transHandle as transHandle */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Sbuffer_Append32(response, t1TpmTransportInternal->transHandle); } if (returnCode == TPM_SUCCESS) { /* checkpoint the beginning of the outParam's */ outParamStart = response->buffer_current - response->buffer; /* return locality */ returnCode = TPM_Sbuffer_Append32(response, tpm_state->tpm_stany_flags.localityModifier); } /* return currentTicks */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CurrentTicks_Store(response, ¤tTicks); } if (returnCode == TPM_SUCCESS) { /* return transNonceEven */ returnCode = TPM_Nonce_Store(response, transNonceEven); /* 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, *hmacKey, /* owner 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); } if (((rcf != 0) || ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING))) && trans_session_added) { TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, t1TpmTransportInternal->transHandle, &(tpm_state->tpm_stany_flags.transportExclusive)); } /* cleanup */ TPM_TransportPublic_Delete(&transPublic); /* @1 */ TPM_SizedBuffer_Delete(&secret); /* @2 */ TPM_TransportAuth_Delete(&k1TransportAuth); /* @4 */ TPM_TransportLogIn_Delete(&l1TransportLogIn); /* @5 */ TPM_TransportLogOut_Delete(&l2TransportLogOut); /* @6 */ TPM_Sbuffer_Delete(&transPublicSbuffer); /* @7 */ TPM_Sbuffer_Delete(¤tTicksSbuffer); /* @8 */ return rcf; } /* 24.2 TPM_ExecuteTransport rev 117 Delivers a wrapped TPM command to the TPM where the TPM unwraps the command and then executes the command. TPM_ExecuteTransport uses the same rolling nonce paradigm as other authorized TPM commands. The even nonces start in EstablishTransport and change on each invocation of TPM_ExecuteTransport. The only restriction on what can happen inside of a transport session is that there is no "nesting" of sessions. It is permissible to perform operations that delete internal state and make the TPM inoperable. Because, in general, key handles are not logged, a digest of the corresponding public key is logged. In cases where the key handle is logged (e.g. TPM_OwnerReadInternalPub), the public key is also logged. The wrapped command is audited twice - once according to the actions of TPM_ExecuteTransport and once within the wrapped command itself according to the special rules for auditing a command wrapped in an encrypted transport session. */ TPM_RESULT TPM_Process_ExecuteTransport(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 wrappedCmd; /* The wrapped command */ TPM_TRANSHANDLE transHandle; /* The transport session handle */ TPM_NONCE transNonceOdd; /* Nonce generated by caller */ TPM_BOOL continueTransSession; /* The continue use flag for the authorization session handle */ TPM_AUTHDATA transAuth; /* HMAC for transHandle key: transHandle -> authData */ /* 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 transHandleValid = FALSE; TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal; TPM_TRANSPORT_INTERNAL t1TransportCopy; /* because original might be invalidated */ TPM_BOOL transportWrappable; /* inner command can be wrapped in transport */ uint32_t keyHandles; /* number of key handles in ordw */ uint32_t keyHandle1Index; /* index of key handles in wrapped command */ uint32_t keyHandle2Index; TPM_KEY_HANDLE keyHandle1; /* key handles in wrapped command */ TPM_KEY_HANDLE keyHandle2; uint32_t blockSize; /* symmetric key block size, if needed */ TPM_RESOURCE_TYPE wrappedResourceType; /* for key handle special cases */ TPM_COMMAND_CODE ordw; /* wrapped ORDW */ uint32_t e1Dataw; /* index into wrapped E1 */ uint32_t len1; /* wrapped LEN1 */ unsigned char *g1Mgf1; /* input MGF1 XOR string */ unsigned char *g2Mgf1; /* output MGF1 XOR string */ unsigned char *decryptCmd; /* decrypted wrapped command */ unsigned char *cmdStream; /* temporary for constructing decryptCmd */ uint32_t cmdStreamSize; TPM_COMMAND_CODE nOrdw; /* ordinal in nbo */ TPM_COMMAND_CODE nOrdet; /* ordinal in nbo */ uint32_t nWrappedCmdSize; /* wrappedCmdSize in nbo */ TPM_DIGEST h1InWrappedDigest; TPM_DIGEST h2OutWrappedDigest; TPM_TRANSPORT_LOG_IN l2TransportLogIn; TPM_TRANSPORT_LOG_OUT l3TransportLogOut; TPM_DIGEST k2PubkeyDigest; TPM_DIGEST k3PubkeyDigest; TPM_KEY *k2Key; /* wrapped command keys */ TPM_KEY *k3Key; TPM_BOOL parentPCRStatus; TPM_STORE_BUFFER wrappedRspSbuffer; const unsigned char *wrappedRspStream; uint32_t wrappedRspStreamSize; uint32_t s2Dataw; /* index into S2 */ uint32_t len2; /* length of S2 */ TPM_RESULT rcw; /* wrapped return code */ TPM_RESULT nRcw; /* return code in nbo */ TPM_STORE_BUFFER currentTicksSbuffer; const unsigned char *currentTicksBuffer; /* serialized buffer */ uint32_t currentTicksLength; /* serialization length */ TPM_RESULT nRCet; /* return code in nbo */ TPM_MODIFIER_INDICATOR nLocality; /* locality in nbo */ uint32_t nWrappedRspStreamSize; /* wrappedRspStreamSize in nbo */ unsigned char *encryptRsp; /* encrypted response */ /* output parameters */ TPM_DIGEST outParamDigest; TPM_UINT64 currentTicks; /* The current ticks when the command was executed */ TPM_SIZED_BUFFER wrappedRsp; /* The wrapped response */ printf("TPM_Process_ExecuteTransport: Ordinal Entry\n"); transportInternal = transportInternal; /* TPM_ExecuteTransport cannot be wrapped */ TPM_SizedBuffer_Init(&wrappedCmd); /* freed @1 */ TPM_SizedBuffer_Init(&wrappedRsp); /* freed @2 */ g1Mgf1 = NULL; /* freed @3 */ decryptCmd = NULL; /* freed @4 */ TPM_TransportLogIn_Init(&l2TransportLogIn); /* freed @5 */ TPM_TransportLogOut_Init(&l3TransportLogOut); /* freed @6 */ TPM_Sbuffer_Init(&wrappedRspSbuffer); /* freed @7 */ TPM_Sbuffer_Init(¤tTicksSbuffer); /* freed @8 */ g2Mgf1 = NULL; /* freed @9 */ TPM_TransportInternal_Init(&t1TransportCopy); /* freed @10 */ encryptRsp = NULL; /* freed @11 */ /* get inputs */ if (returnCode == TPM_SUCCESS) { /* save the starting point of inParam's for authorization and auditing */ /* inParamStart = command; */ /* get wrappedCmd */ returnCode = TPM_SizedBuffer_Load(&wrappedCmd, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: wrapped command size %u\n", wrappedCmd.size); /* save the ending point of inParam's for authorization and auditing */ /* inParamEnd = command; */ /* NOTE: The common TPM_GetInParamDigest() is not called here, since inParamDigest cannot be calculated until the wrapped command is decrypted */ returnCode = TPM_OrdinalAuditStatus_GetAuditStatus(&auditStatus, ordinal, &(tpm_state->tpm_permanent_data)); } /* 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(&transHandle, &transHandleValid, transNonceOdd, &continueTransSession, transAuth, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: transHandle %08x\n", transHandle); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_ExecuteTransport: 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) { transHandleValid = FALSE; } /* Processing */ /* if there is an active exclusive transport session and it's not this session, terminate it */ if (returnCode == TPM_SUCCESS) { if ((tpm_state->tpm_stany_flags.transportExclusive != 0) && (tpm_state->tpm_stany_flags.transportExclusive != transHandle)) { returnCode = TPM_TransportSessions_TerminateHandle (tpm_state->tpm_stclear_data.transSessions, tpm_state->tpm_stany_flags.transportExclusive, &(tpm_state->tpm_stany_flags.transportExclusive)); } } /* 1. Using transHandle locate the TPM_TRANSPORT_INTERNAL structure T1 */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportSessions_GetEntry(&t1TpmTransportInternal, tpm_state->tpm_stclear_data.transSessions, transHandle); } /* For the corner case where the wrapped command invalidates the transport session, make a copy for the response. */ if (returnCode == TPM_SUCCESS) { TPM_TransportInternal_Copy(&t1TransportCopy, t1TpmTransportInternal); } /* 2. Parse wrappedCmd */ /* a. Set TAGw, LENw, and ORDw to the parameters from wrappedCmd */ /* b. Set E1 to DATAw */ /* i. This pointer is ordinal dependent and requires the execute transport command to parse wrappedCmd */ /* c. Set LEN1 to the length of DATAw */ /* i. DATAw always ends at the start of AUTH1w if AUTH1w is present */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_OrdinalTable_ParseWrappedCmd(&e1Dataw, /* index into wrappedCmd */ &len1, &keyHandles, &keyHandle1Index, /* index into key handles */ &keyHandle2Index, &ordw, &transportWrappable, &wrappedCmd); if (returnCode != TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: Error parsing wrapped command\n"); } } /* 3. If LEN1 is less than 0, or if ORDw is unknown, unimplemented, or cannot be determined a. Return TPM_BAD_PARAMETER */ if (returnCode == TPM_SUCCESS) { if (wrappedCmd.size < e1Dataw + len1) { printf("TPM_Process_ExecuteTransport: Error (fatal), wrappedCmdSize %u e1 %u len1 %u\n", wrappedCmd.size, e1Dataw, len1); returnCode = TPM_FAIL; /* internal error, should never occur */ } } /* allocate memory for the decrypted command, which is always the same length as the encrypted command */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Malloc(&decryptCmd, wrappedCmd.size); } /* 4. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT set then */ if ((returnCode == TPM_SUCCESS) && (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) && (len1 != 0)) { /* some commands have no DATAw area to encrypt */ /* a. If T1 -> transPublic -> algId is TPM_ALG_MGF1 */ if (t1TransportCopy.transPublic.algId == TPM_ALG_MGF1) { printf("TPM_Process_ExecuteTransport: Wrapped command MGF1 encrypted\n"); /* i. Using the MGF1 function, create string G1 of length LEN1. The inputs to the MGF1 are transLastNonceEven, transNonceOdd, "in", and T1 -> authData. These four values concatenated together form the Z value that is the seed for the MGF1. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_MGF1_GenerateArray(&g1Mgf1, /* G1 MGF1 array */ len1, /* G1 length */ TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("in") - 1 + TPM_AUTHDATA_SIZE, /* seed length */ TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, TPM_NONCE_SIZE, transNonceOdd, sizeof("in") - 1, "in", TPM_AUTHDATA_SIZE, t1TransportCopy.authData, 0, NULL); } /* ii. Create C1 by performing an XOR of G1 and wrappedCmd starting at E1. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Transport_CryptMgf1(decryptCmd, /* output */ wrappedCmd.buffer, /* input */ g1Mgf1, /* XOR pad */ wrappedCmd.size, /* total size of buffers */ e1Dataw, /* start of encrypted part */ len1); /* length of encrypted part */ } } /* b. If the encryption algorithm requires an IV or CTR calculate the IV or CTR value */ else { printf("TPM_Process_ExecuteTransport: " "Wrapped command algId %08x encScheme %04hx encrypted\n", t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme); /* This function call should not fail, as the parameters were checked at TPM_EstablishTransport. The call is used here to get the block size. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportPublic_CheckEncScheme(&blockSize, t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme, tpm_state->tpm_permanent_flags.FIPS); } /* i. Using the MGF1 function, create string IV1 or CTR1 with a length set by the block size of the encryption algorithm. The inputs to the MGF1 are transLastNonceEven, transNonceOdd, and "in". These three values concatenated together form the Z value that is the seed for the MGF1. Note that any terminating characters within the string "in" are ignored, so a total of 42 bytes are hashed. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_MGF1_GenerateArray(&g1Mgf1, /* G1 MGF1 array */ blockSize, /* G1 length */ TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("in") - 1, /* seed length */ TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, TPM_NONCE_SIZE, transNonceOdd, sizeof("in") - 1, "in", 0, NULL); } /* ii. The symmetric key is taken from the first bytes of T1 -> authData. */ /* iii. Decrypt DATAw and replace the DATAw area of E1 creating C1 */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Transport_CryptSymmetric(decryptCmd, /* output */ wrappedCmd.buffer, /* input */ t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme, t1TransportCopy.authData, /* key */ TPM_AUTHDATA_SIZE, /* key size */ g1Mgf1, /* pad, IV or CTR */ blockSize, wrappedCmd.size, /* total size of buffers */ e1Dataw, /* start of encrypted part */ len1); /* length of encrypted part */ } } /* 4.c. TPM_OSAP, TPM_OIAP have no parameters encrypted */ /* NOTE Handled by len1 = 0 */ /* 4.d. TPM_DSAP has special rules for parameter encryption */ /* NOTE Handled by setting inputHandleSize to all but entityValue */ } /* 5. Else (no encryption) */ else if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: Wrapped command not encrypted\n"); /* a. Set C1 to the DATAw area E1 of wrappedCmd */ memcpy(decryptCmd, wrappedCmd.buffer, wrappedCmd.size); } /* Now that the wrapped command is decrypted, handle the special cases (e.g., TPM_FlushSpecific and TPM_SaveContext) where the handle may or may not be a key handle, dependent on the value of resourceType */ if ((returnCode == TPM_SUCCESS) && (keyHandles == 0xffffffff)) { printf("TPM_Process_ExecuteTransport: key handles special case\n"); /* point to the resourceType in the decrypted stream, directly after the key handle */ cmdStream = decryptCmd + keyHandle1Index + sizeof(TPM_KEY_HANDLE); cmdStreamSize = wrappedCmd.size - keyHandle1Index - sizeof(TPM_KEY_HANDLE); returnCode = TPM_Load32(&wrappedResourceType, &cmdStream , &cmdStreamSize ); } /* ii. If the resourceType is TPM_RT_KEY, then the public key MUST be logged */ if ((returnCode == TPM_SUCCESS) && (keyHandles == 0xffffffff)) { printf("TPM_Process_ExecuteTransport: special case resource type %08x\n", wrappedResourceType); if (wrappedResourceType == TPM_RT_KEY) { printf("TPM_Process_ExecuteTransport: Special case, 1 key handle\n"); keyHandles = 1; } else { keyHandles = 0; } } /* 6. Create H1 the SHA-1 of (ORDw || C1). */ /* a. C1 MUST point at the decrypted DATAw area of E1 */ /* b. The TPM MAY use this calculation for both execute transport authorization, authorization of the wrapped command and transport log creation */ if (returnCode == TPM_SUCCESS) { TPM_PrintFour("TPM_Process_ExecuteTransport: DATAw decrypted", decryptCmd); printf("TPM_Process_ExecuteTransport: Create H1\n"); nOrdw = htonl(ordw); returnCode = TPM_SHA1(h1InWrappedDigest, sizeof(TPM_COMMAND_CODE), &nOrdw, len1, decryptCmd + e1Dataw, 0, NULL); } /* 7. Validate the incoming transport session authorization */ /* a. Set inParamDigest to SHA-1 (ORDet || wrappedCmdSize || H1) */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: Validate AUTHet\n"); nOrdet = htonl(ordinal); nWrappedCmdSize = htonl(wrappedCmd.size); returnCode = TPM_SHA1(inParamDigest, sizeof(TPM_COMMAND_CODE), &nOrdet, sizeof(uint32_t), &nWrappedCmdSize, TPM_DIGEST_SIZE, h1InWrappedDigest, 0, NULL); } /* b. Calculate the HMAC of (inParamDigest || transLastNonceEven || transNonceOdd || continueTransSession) using T1 -> authData as the HMAC key */ /* c. Validate transAuth, on errors return TPM_AUTHFAIL */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportInternal_Check(inParamDigest, &t1TransportCopy, /* transport session */ transNonceOdd, /* Nonce generated by system associated with authHandle */ continueTransSession, transAuth); /* Authorization digest for input */ } /* 8. If TPM_ExecuteTransport requires auditing */ /* a. Create TPM_AUDIT_EVENT_IN using H1 */ /* NOTE: Done during response */ /* 9. If ORDw is from the list of following commands return TPM_NO_WRAP_TRANSPORT */ /* a. TPM_EstablishTransport */ /* b. TPM_ExecuteTransport */ /* c. TPM_ReleaseTransportSigned */ if (returnCode == TPM_SUCCESS) { if (!transportWrappable) { printf("TPM_Process_ExecuteTransport: Error, ordinal %08x cannot be wrapped\n", ordw); returnCode = TPM_NO_WRAP_TRANSPORT; } } /* 10. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */ if ((returnCode == TPM_SUCCESS) && (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_LOG)) { printf("TPM_Process_ExecuteTransport: Create transport log\n"); /* a. Create L2 a TPM_TRANSPORT_LOG_IN structure */ /* NOTE Done by TPM_TransportLogIn_Init() */ /* b. Set L2 -> parameters to H1 */ TPM_Digest_Copy(l2TransportLogIn.parameters, h1InWrappedDigest); /* c. If ORDw is a command with no key handles */ /* i. Set L2 -> pubKeyHash to NULL */ /* NOTE Done by TPM_TransportLogIn_Init() */ if ((returnCode == TPM_SUCCESS) && ((keyHandles == 1) || (keyHandles == 2))) { if (returnCode == TPM_SUCCESS) { /* point to the first key handle in the decrypted stream */ cmdStream = decryptCmd + keyHandle1Index; cmdStreamSize = wrappedCmd.size - keyHandle1Index; /* get the key handle */ returnCode = TPM_Load32(&keyHandle1, &cmdStream, &cmdStreamSize); } /* get the first key */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: Create pubKeyHash for key 1 handle %08x\n", keyHandle1); returnCode = TPM_KeyHandleEntries_GetKey(&k2Key, &parentPCRStatus, tpm_state, keyHandle1, TRUE, /* read-only */ FALSE, /* do not ignore PCRs */ TRUE); /* can use EK */ } /* 10.d. If ORDw is a command with one key handle */ /* 10.i. Create K2 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by the key handle. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SHA1_GenerateStructure(k2PubkeyDigest, &(k2Key->pubKey), (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store); } } if ((returnCode == TPM_SUCCESS) && (keyHandles == 1)) { printf("TPM_Process_ExecuteTransport: Digesting one public key\n"); /* 10.ii. Set L2 -> pubKeyHash to SHA-1 (K2) */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SHA1(l2TransportLogIn.pubKeyHash, TPM_DIGEST_SIZE, k2PubkeyDigest, 0, NULL); } } /* 10.e. If ORDw is a command with two key handles */ if ((returnCode == TPM_SUCCESS) && (keyHandles == 2)) { printf("TPM_Process_ExecuteTransport: Digesting two public keys\n"); /* i. Create K2 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by the first key handle. */ /* NOTE Done above for 1 or 2 key case */ if (returnCode == TPM_SUCCESS) { /* point to the second key handle in the decrypted stream */ cmdStream = decryptCmd + keyHandle2Index; cmdStreamSize = wrappedCmd.size - keyHandle2Index; /* get the key handle */ returnCode = TPM_Load32(&keyHandle2, &cmdStream, &cmdStreamSize); } /* get the second key */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: Create pubKeyHash for key 2 handle %08x\n", keyHandle2); returnCode = TPM_KeyHandleEntries_GetKey(&k3Key, &parentPCRStatus, tpm_state, keyHandle2, TRUE, /* read-only */ FALSE, /* do not ignore PCRs */ TRUE); /* can use EK */ } /* ii. Create K3 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by the second key handle. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SHA1_GenerateStructure(k3PubkeyDigest, &(k3Key->pubKey), (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store); } /* 10.iii. Set L2 -> pubKeyHash to SHA-1 (K2 || K3) */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SHA1(l2TransportLogIn.pubKeyHash, TPM_DIGEST_SIZE, k2PubkeyDigest, TPM_DIGEST_SIZE, k3PubkeyDigest, 0, NULL); } } /* 10.f. Set T1 -> transDigest to the SHA-1 (T1 -> transDigest || L2) */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: Extend transDigest with input\n"); returnCode = TPM_TransportLogIn_Extend(t1TransportCopy.transDigest, &l2TransportLogIn); } /* 10.g. If ORDw is a command with key handles, and the key is not loaded, return TPM_INVALID_KEYHANDLE. */ /* NOTE Done by TPM_KeyHandleEntries_GetKey() */ } /* 11. Send the wrapped command to the normal TPM command parser, the output is C2 and the return code is RCw */ /* a. If ORDw is a command that is audited then the TPM MUST perform the input and output audit of the command as part of this action */ /* b. The TPM MAY use H1 as the data value in the authorization and audit calculations during the execution of C1 */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: Call wrapped command\n"); returnCode = TPM_Process_Wrapped(&wrappedRspSbuffer, /* response buffer */ decryptCmd, /* complete command array */ wrappedCmd.size, /* actual bytes in command */ tpm_state, &t1TransportCopy); /* TPM_ExecuteTransport */ printf("TPM_Process_ExecuteTransport: Completed wrapped command\n"); } /* 12. Set CT1 to TPM_STANY_DATA -> currentTicks -> currentTicks and return CT1 in the currentTicks output parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CurrentTicks_Update(&(tpm_state->tpm_stany_data.currentTicks)); } if (returnCode == TPM_SUCCESS) { TPM_Uint64_Copy(¤tTicks, &(tpm_state->tpm_stany_data.currentTicks.currentTicks)); } if (returnCode == TPM_SUCCESS) { returnCode = TPM_Uint64_Store(¤tTicksSbuffer, &(tpm_state->tpm_stany_data.currentTicks.currentTicks)); } /* 13. Calculate S2 the pointer to the DATAw area of C2 */ /* a. Calculate LEN2 the length of S2 according to the same rules that calculated LEN1 */ if (returnCode == TPM_SUCCESS) { /* get the response buffer and length */ TPM_Sbuffer_Get(&wrappedRspSbuffer, &wrappedRspStream, &wrappedRspStreamSize); /* parse the three standard input parameters, check paramSize against wrappedRsp->size */ returnCode = TPM_OrdinalTable_ParseWrappedRsp(&s2Dataw, &len2, &rcw, ordw, wrappedRspStream, wrappedRspStreamSize); } /* 14. Create H2 the SHA-1 of (RCw || ORDw || S2) */ /* a. The TPM MAY use this calculation for execute transport authorization and transport log out creation */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: Create H2\n"); nRcw = htonl(rcw); /* The TPM_ExecuteTransport input ordinal and output ordinal, currentTicks and locality are not audited. This was simply an error, and not a deliberate attempt to make TPM_ExecuteTransport different from other ordinals. */ returnCode = TPM_SHA1(h2OutWrappedDigest, sizeof(TPM_RESULT), &nRcw, sizeof(TPM_COMMAND_CODE), &nOrdw, len2, wrappedRspStream + s2Dataw, 0, NULL); } /* 15. Calculate the outgoing transport session authorization */ /* a. Create the new transNonceEven for the output of the command */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Nonce_Generate(t1TransportCopy.transNonceEven); } /* b. Set outParamDigest to SHA-1 (RCet || ORDet || TPM_STANY_DATA -> currentTicks -> currentTicks || locality || wrappedRspSize || H2) */ if (returnCode == TPM_SUCCESS) { nRCet = htonl(returnCode); TPM_Sbuffer_Get(¤tTicksSbuffer, ¤tTicksBuffer, ¤tTicksLength); nLocality = htonl(tpm_state->tpm_stany_flags.localityModifier); nWrappedRspStreamSize = htonl(wrappedRspStreamSize); returnCode = TPM_SHA1(outParamDigest, sizeof(TPM_RESULT), &nRCet, sizeof(TPM_COMMAND_CODE), &nOrdet, currentTicksLength, currentTicksBuffer, sizeof(TPM_MODIFIER_INDICATOR), &nLocality, sizeof(uint32_t), &nWrappedRspStreamSize, TPM_DIGEST_SIZE, h2OutWrappedDigest, 0, NULL); } /* c. Calculate transAuth, the HMAC of (outParamDigest || transNonceEven || transNonceOdd || continueTransSession) using T1 -> authData as the HMAC key */ /* NOTE: Done as part of response */ /* 16. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */ if ((returnCode == TPM_SUCCESS) && (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_LOG)) { /* a. Create L3 a TPM_TRANSPORT_LOG_OUT structure */ /* NOTE Done by TPM_TransportLogOut_Init() */ /* b. Set L3 -> parameters to H2 */ TPM_Digest_Copy(l3TransportLogOut.parameters, h2OutWrappedDigest); /* c. Set L3 -> currentTicks to TPM_STANY_DATA -> currentTicks */ TPM_CurrentTicks_Copy(&(l3TransportLogOut.currentTicks), &(tpm_state->tpm_stany_data.currentTicks)); /* d. Set L3 -> locality to TPM_STANY_DATA -> localityModifier */ l3TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier; /* e. Set T1 -> transDigest to the SHA-1 (T1 -> transDigest || L3) */ printf("TPM_Process_ExecuteTransport: Extend transDigest with output\n"); returnCode = TPM_TransportLogOut_Extend(t1TransportCopy.transDigest, &l3TransportLogOut); } /* allocate memory for the encrypted response, which is always the same length as the decrypted response */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Malloc(&encryptRsp, wrappedRspStreamSize); } /* 17. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT set then */ if ((returnCode == TPM_SUCCESS) && (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) && (len2 != 0)) { /* some commands have no DATAw area to encrypt */ /* NOTE No TPM_OSAP encryption handled by len2 = 0 */ /* a. If T1 -> transPublic -> algId is TPM_ALG_MGF1 */ if (t1TransportCopy.transPublic.algId == TPM_ALG_MGF1) { printf("TPM_Process_ExecuteTransport: Wrapped response MGF1 encrypted\n"); /* i. Using the MGF1 function, create string G2 of length LEN2. The inputs to the MGF1 are transNonceEven, transNonceOdd, "out", and T1 -> authData. These four values concatenated together form the Z value that is the seed for the MGF1. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_MGF1_GenerateArray(&g2Mgf1, /* G2 MGF1 array */ len2, /* G2 length */ TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("out") - 1 + TPM_AUTHDATA_SIZE, /* seed length */ TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, TPM_NONCE_SIZE, transNonceOdd, sizeof("out") - 1, "out", TPM_AUTHDATA_SIZE, t1TransportCopy.authData, 0, NULL); } /* ii. Create E2 by performing an XOR of G2 and C2 starting at S2. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Transport_CryptMgf1(encryptRsp, wrappedRspStream, g2Mgf1, wrappedRspStreamSize, s2Dataw, len2); } } /* b. Else */ else { printf("TPM_Process_ExecuteTransport: " "Wrapped response algId %08x encScheme %04hx encrypted\n", t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme); /* This function call should not fail, as the parameters were checked at TPM_EstablishTransport. The call is used here to get the block size. This is a duplicate of the call for the command. However, there are cases where there is no encrypted command (len1 == 0) so the call was not made. Rather than keep track of whether blockSize is valid, it's clearer to just call the function twice in some cases. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportPublic_CheckEncScheme(&blockSize, t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme, tpm_state->tpm_permanent_flags.FIPS); } /* i. Create IV2 or CTR2 using the same algorithm as IV1 or CTR1 with the input values transNonceEven, transNonceOdd, and "out". Note that any terminating characters within the string "out" are ignored, so a total of 43 bytes are hashed. */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_MGF1_GenerateArray(&g2Mgf1, /* G2 MGF1 array */ blockSize, /* G2 length */ TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("out") - 1, /* seed length */ TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, TPM_NONCE_SIZE, transNonceOdd, sizeof("out") - 1, "out", 0, NULL); } /* ii. The symmetric key is taken from the first bytes of T1 -> authData */ /* iii. Create E2 by encrypting C2 starting at S2 */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Transport_CryptSymmetric(encryptRsp, /* output */ wrappedRspStream, /* input */ t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme, t1TransportCopy.authData, /* key */ TPM_AUTHDATA_SIZE, /* key size */ g2Mgf1, /* pad, IV or CTR */ blockSize, wrappedRspStreamSize, /* total size of buffers */ s2Dataw, /* start of encrypted part */ len2); /* length of encrypted part */ } } } /* 18. Else (no encryption) */ else if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ExecuteTransport: Wrapped response not encrypted\n"); /* a. Set E2 to the DATAw area S2 of wrappedRsp */ memcpy(encryptRsp, wrappedRspStream ,wrappedRspStreamSize); } /* 19. If continueTransSession is FALSE */ /* a. Invalidate all session data related to transHandle */ /* NOTE: Done after response */ /* 20. If TPM_ExecuteTranport requires auditing */ /* a. Create TPM_AUDIT_EVENT_OUT using H2 */ /* NOTE: Done during response */ /* 21. Return C2 but with S2 replaced by E2 in the wrappedRsp parameter */ if (returnCode == TPM_SUCCESS) { /* if the wrapped command invalidated the transport session, set continueTransSession to FALSE */ if (!(t1TpmTransportInternal->valid)) { continueTransSession = FALSE; } /* if the session is still valid, copy the copy back to the original so the log gets updated */ else { TPM_TransportInternal_Copy(t1TpmTransportInternal, &t1TransportCopy); } } /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_ExecuteTransport: 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) { /* return currentTicks */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Sbuffer_Append(response, currentTicksBuffer, currentTicksLength); } /* return locality */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Sbuffer_Append32(response, tpm_state->tpm_stany_flags.localityModifier); } /* return wrappedRspSize */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Sbuffer_Append32(response, wrappedRspStreamSize); } /* return wrappedRsp */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_Sbuffer_Append(response, encryptRsp, wrappedRspStreamSize); } /* non-standard - digest the above the line output parameters, H1 used */ /* non-standard - calculate and set the below the line parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportInternal_Set(response, &t1TransportCopy, outParamDigest, transNonceOdd, continueTransSession, FALSE); /* transNonceEven already generated */ } /* audit if required */ if ((returnCode == TPM_SUCCESS) && auditStatus) { returnCode = TPM_ProcessAudit(tpm_state, FALSE, /* transportEncrypt */ h1InWrappedDigest, h2OutWrappedDigest, /* exception to normal digest */ ordinal); } /* adjust the initial response */ rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); } /* if there was an error, or continueTransSession is FALSE, terminate the session */ if (((rcf != 0) || ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || !continueTransSession) && transHandleValid) { TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, transHandle, &(tpm_state->tpm_stany_flags.transportExclusive)); } /* cleanup */ TPM_SizedBuffer_Delete(&wrappedCmd); /* @1 */ TPM_SizedBuffer_Delete(&wrappedRsp); /* @2 */ free(g1Mgf1); /* @3 */ free (decryptCmd); /* @4 */ TPM_TransportLogIn_Delete(&l2TransportLogIn); /* @5 */ TPM_TransportLogOut_Delete(&l3TransportLogOut); /* @6 */ TPM_Sbuffer_Delete(&wrappedRspSbuffer); /* @7 */ TPM_Sbuffer_Delete(¤tTicksSbuffer); /* @8 */ free(g2Mgf1); /* @9 */ TPM_TransportInternal_Delete(&t1TransportCopy); /* @10 */ free(encryptRsp); /* @11 */ return rcf; } /* 24.3 TPM_ReleaseTransportSigned rev 101 This command completes the transport session. If logging for this session is turned on, then this command returns a hash of all operations performed during the session along with a digital signature of the hash. This command serves no purpose if logging is turned off, and results in an error if attempted. This command uses two authorization sessions, the key that will sign the log and the authorization from the session. Having the session authorization proves that the requester that is signing the log is the owner of the session. If this restriction is not put in then an attacker can close the log and sign using their own key. The hash of the session log includes the information associated with the input phase of execution of the TPM_ReleaseTransportSigned command. It cannot include the output phase information. */ TPM_RESULT TPM_Process_ReleaseTransportSigned(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; /* Handle of a loaded key that will perform the signing */ TPM_NONCE antiReplay; /* Value provided by caller for anti-replay protection */ TPM_AUTHHANDLE authHandle; /* The authorization session to use key */ TPM_NONCE authNonceOdd; /* Nonce generated by system associated with authHandle */ TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session handle */ TPM_AUTHDATA keyAuth; /* The authorization session digest that authorizes the use of key. HMAC key: key -> usageAuth */ TPM_TRANSHANDLE transHandle; /* The transport session handle */ TPM_NONCE transNonceOdd; /* Nonce supplied by caller for transport session */ TPM_BOOL continueTransSession = TRUE; /* The continue use flag for the authorization session handle */ TPM_AUTHDATA transAuth; /* HMAC for transport session key: tranHandle -> authData */ /* 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_BOOL transHandleValid = FALSE; TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal = NULL; TPM_SECRET *hmacKey; TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ TPM_BOOL parentPCRStatus; TPM_SECRET *keyUsageAuth; TPM_TRANSPORT_LOG_OUT a1TransportLogOut; TPM_SIGN_INFO h1SignInfo; TPM_DIGEST h1Digest; /* digest of h1SignInfo */ /* output parameters */ uint32_t outParamStart; /* starting point of outParam's */ uint32_t outParamEnd; /* ending point of outParam's */ TPM_DIGEST outParamDigest; TPM_CURRENT_TICKS *currentTicks = NULL; /* The current time according to the TPM */ TPM_SIZED_BUFFER signature; /* The signature of the digest */ printf("TPM_Process_ReleaseTransportSigned: Ordinal Entry\n"); TPM_SizedBuffer_Init(&signature); /* freed @1 */ TPM_TransportLogOut_Init(&a1TransportLogOut); /* freed @2 */ TPM_SignInfo_Init(&h1SignInfo); /* freed @3 */ /* 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 antiReplay */ if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ReleaseTransportSigned: keyHandle %08x\n", keyHandle ); returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); } /* save the ending point of inParam's for authorization and auditing */ inParamEnd = command; /* digest the input parameters */ if (returnCode == TPM_SUCCESS) { TPM_PrintFour("TPM_Process_ReleaseTransportSigned: antiReplay", antiReplay); 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_CheckRequestTag21(tag); } /* get the optional 'below the line' authorization parameters */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_AuthParams_Get(&authHandle, &authHandleValid, authNonceOdd, &continueAuthSession, keyAuth, &command, ¶mSize); printf("TPM_Process_ReleaseTransportSigned: authHandle %08x\n", authHandle); } /* get the 'below the line' authorization parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_AuthParams_Get(&transHandle, &transHandleValid, transNonceOdd, &continueTransSession, transAuth, &command, ¶mSize); } if (returnCode == TPM_SUCCESS) { printf("TPM_Process_ReleaseTransportSigned: transHandle %08x\n", transHandle); } if (returnCode == TPM_SUCCESS) { if (paramSize != 0) { printf("TPM_Process_ReleaseTransportSigned: 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) { transHandleValid = FALSE; } /* Processing */ /* if there is an active exclusive transport session and it's not this session, terminate it */ if (returnCode == TPM_SUCCESS) { if ((tpm_state->tpm_stany_flags.transportExclusive != 0) && (tpm_state->tpm_stany_flags.transportExclusive != transHandle)) { returnCode = TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, tpm_state->tpm_stany_flags.transportExclusive, &(tpm_state->tpm_stany_flags.transportExclusive)); } } /* 1. Using transHandle locate the TPM_TRANSPORT_INTERNAL structure T1 */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportSessions_GetEntry(&t1TpmTransportInternal, tpm_state->tpm_stclear_data.transSessions, transHandle); } /* get the key corresponding to the keyHandle parameter */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, FALSE, /* not r/o, used to sign */ FALSE, /* do not ignore PCRs */ FALSE); /* cannot use EK */ } /* 2. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO, if not return TPM_INAPPROPRIATE_SIG. */ if (returnCode == TPM_SUCCESS) { if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { printf("TPM_Process_ReleaseTransportSigned: Error, invalid sigKey sigScheme %04hx\n", sigKey->algorithmParms.sigScheme); returnCode = TPM_INAPPROPRIATE_SIG; } } if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { if (sigKey->authDataUsage != TPM_AUTH_NEVER) { printf("TPM_Process_ReleaseTransportSigned: Error, authorization required\n"); returnCode = TPM_AUTHFAIL; } } /* get keyHandle -> usageAuth */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); } /* get the session data */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_AuthSessions_GetData(&auth_session_data, &hmacKey, tpm_state, authHandle, TPM_PID_NONE, TPM_ET_KEYHANDLE, ordinal, sigKey, keyUsageAuth, /* OIAP */ sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ } /* 3. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, if not return TPM_INVALID_KEYUSAGE */ if (returnCode == TPM_SUCCESS) { if (sigKey ->keyUsage != TPM_KEY_SIGNING) { printf("TPM_Process_ReleaseTransportSigned: Error, keyUsage %04hx is invalid\n", sigKey ->keyUsage); returnCode = TPM_INVALID_KEYUSAGE; } } /* 4. Using key -> authData validate the command and parameters, on error return TPM_AUTHFAIL */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_Authdata_Check(tpm_state, *hmacKey, /* HMAC key */ inParamDigest, auth_session_data, /* authorization session */ authNonceOdd, /* Nonce generated by system associated with authHandle */ continueAuthSession, keyAuth); /* Authorization digest for input */ } /* 5. Using transHandle -> authData validate the command and parameters, on error return TPM_AUTH2FAIL */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportInternal_Check(inParamDigest, t1TpmTransportInternal, /* transport session */ transNonceOdd, /* Nonce generated by system associated with authHandle */ continueTransSession, transAuth); /* Authorization digest for input */ } /* 7. Else */ if (returnCode == TPM_SUCCESS) { if (!(t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_LOG)) { /* a. Return TPM_BAD_MODE */ printf("TPM_Process_ReleaseTransportSigned: Error, TPM_TRANSPORT_LOG not set\n"); returnCode = TPM_BAD_MODE; } } /* 6. If T1 -> transAttributes has TPM_TRANSPORT_LOG set then update the current ticks structure */ if (returnCode == TPM_SUCCESS) { currentTicks = &(tpm_state->tpm_stany_data.currentTicks); /* update the ticks based on the current time */ returnCode = TPM_CurrentTicks_Update(currentTicks); } if (returnCode == TPM_SUCCESS) { /* a. Create A1 a TPM_TRANSPORT_LOG_OUT structure */ /* NOTE Done by TPM_TransportLogOut_Init() */ /* b. Set A1 -> parameters to the SHA-1 (ordinal || antiReplay) */ TPM_Digest_Copy(a1TransportLogOut.parameters, inParamDigest); /* c. Set A1 -> currentTicks to TPM_STANY_DATA -> currentTicks */ TPM_CurrentTicks_Copy(&(a1TransportLogOut.currentTicks), currentTicks); /* d. Set A1 -> locality to the locality modifier for this command */ a1TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier; /* e. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || A1) */ printf("TPM_Process_ReleaseTransportSigned: Extend transDigest with output\n"); returnCode = TPM_TransportLogOut_Extend(t1TpmTransportInternal->transDigest, &a1TransportLogOut); } if (returnCode == TPM_SUCCESS) { /* 8. Create H1 a TPM_SIGN_INFO structure and set the structure defaults */ /* NOTE: Done by TPM_SignInfo_Init() */ /* a. Set H1 -> fixed to "TRAN" */ memcpy(h1SignInfo.fixed, "TRAN", TPM_SIGN_INFO_FIXED_SIZE); /* b. Set H1 -> replay to antiReplay */ TPM_Nonce_Copy(h1SignInfo.replay, antiReplay); /* c. Set H1 -> data to T1 -> transDigest */ returnCode = TPM_SizedBuffer_Set(&(h1SignInfo.data), TPM_DIGEST_SIZE, t1TpmTransportInternal->transDigest); } /* d. Sign SHA-1 hash of H1 using the key pointed to by keyHandle */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_SHA1_GenerateStructure(h1Digest, &h1SignInfo, (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); TPM_PrintAll("TPM_Process_ReleaseTransportSigned: h1Digest", h1Digest, TPM_DIGEST_SIZE); } if (returnCode == TPM_SUCCESS) { returnCode = TPM_RSASignToSizedBuffer(&signature, /* signature */ h1Digest, /* message */ TPM_DIGEST_SIZE, /* message size */ sigKey); /* input, signing key */ } /* 9. Invalidate all session data related to T1 */ /* NOTE Done after response */ /* 10. Set continueTransSession to FALSE */ if (returnCode == TPM_SUCCESS) { continueTransSession = FALSE; } /* 11. Return TPM_SUCCESS */ /* response */ /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ if (rcf == 0) { printf("TPM_Process_ReleaseTransportSigned: 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 locality */ returnCode = TPM_Sbuffer_Append32(response, tpm_state->tpm_stany_flags.localityModifier); } /* return currentTicks */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_CurrentTicks_Store(response, currentTicks); } if (returnCode == TPM_SUCCESS) { /* return signature */ returnCode = TPM_SizedBuffer_Store(response, &signature); /* 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 optional below the line parameters */ if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { returnCode = TPM_AuthParams_Set(response, *hmacKey, /* owner HMAC key */ auth_session_data, outParamDigest, authNonceOdd, continueAuthSession); } /* calculate and set the below the line parameters */ if (returnCode == TPM_SUCCESS) { returnCode = TPM_TransportInternal_Set(response, t1TpmTransportInternal, outParamDigest, transNonceOdd, continueTransSession, TRUE); /* generate transNonceEven */ } /* 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 continueTransSession is FALSE, terminate the session */ if (((rcf != 0) || ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || !continueTransSession) && transHandleValid) { TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, transHandle, &(tpm_state->tpm_stany_flags.transportExclusive)); } /* 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(&signature); /* @1 */ TPM_TransportLogOut_Delete(&a1TransportLogOut); /* @2 */ TPM_SignInfo_Delete(&h1SignInfo); /* @3 */ return rcf; }