diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 21:41:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 21:41:43 +0000 |
commit | 92cccad89d1c12b39165d5f0ed7ccd2d44965a1a (patch) | |
tree | f59a2764cd8c50959050a428bd8fc935138df750 /src/tpm12/tpm_storage.c | |
parent | Initial commit. (diff) | |
download | libtpms-92cccad89d1c12b39165d5f0ed7ccd2d44965a1a.tar.xz libtpms-92cccad89d1c12b39165d5f0ed7ccd2d44965a1a.zip |
Adding upstream version 0.9.2.upstream/0.9.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tpm12/tpm_storage.c')
-rw-r--r-- | src/tpm12/tpm_storage.c | 3593 |
1 files changed, 3593 insertions, 0 deletions
diff --git a/src/tpm12/tpm_storage.c b/src/tpm12/tpm_storage.c new file mode 100644 index 0000000..c3cd1ac --- /dev/null +++ b/src/tpm12/tpm_storage.c @@ -0,0 +1,3593 @@ +/********************************************************************************/ +/* */ +/* Storage Functions */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_storage.c 4442 2011-02-14 20:20:01Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "tpm_auth.h" +#include "tpm_cryptoh.h" +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_structures.h" +#include "tpm_ver.h" + +#include "tpm_storage.h" + +/* local function prototypes */ + +static TPM_RESULT TPM_SealCryptCommon(BYTE **o1, + TPM_ADIP_ENC_SCHEME adipEncScheme, + TPM_SIZED_BUFFER *inData, + TPM_AUTH_SESSION_DATA *auth_session_data, + TPM_NONCE nonceOdd); + +static TPM_RESULT TPM_LoadKeyCommon(TPM_KEY_HANDLE *inKeyHandle, + TPM_BOOL *key_added, + TPM_SECRET **hmacKey, + TPM_AUTH_SESSION_DATA **auth_session_data, + tpm_state_t *tpm_state, + TPM_TAG tag, + TPM_COMMAND_CODE ordinal, + TPM_KEY_HANDLE parentHandle, + TPM_KEY *inKey, + TPM_DIGEST inParamDigest, + TPM_AUTHHANDLE authHandle, + TPM_NONCE nonceOdd, + TPM_BOOL continueAuthSession, + TPM_AUTHDATA parentAuth); + +/* + TPM_BOUND_DATA +*/ + +/* TPM_BoundData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_BoundData_Init(TPM_BOUND_DATA *tpm_bound_data) +{ + printf(" TPM_BoundData_Init:\n"); + TPM_StructVer_Init(&(tpm_bound_data->ver)); + tpm_bound_data->payload = TPM_PT_BIND; + tpm_bound_data->payloadDataSize = 0; + tpm_bound_data->payloadData = NULL; + return; +} + +/* TPM_BoundData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_BoundData_Init() + After use, call TPM_BoundData_Delete() to free memory +*/ + +TPM_RESULT TPM_BoundData_Load(TPM_BOUND_DATA *tpm_bound_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_BoundData_Load:\n"); + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_bound_data->ver), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_bound_data->ver)); + } + if (rc == 0) { + rc = TPM_Load8(&(tpm_bound_data->payload), stream, stream_size); + } + if ((rc == 0) && (*stream_size > 0)){ + /* There is no payloadData size in the serialized data. Assume it consumes the rest of the + stream */ + tpm_bound_data->payloadDataSize = *stream_size; + rc = TPM_Malloc(&(tpm_bound_data->payloadData), tpm_bound_data->payloadDataSize); + } + if ((rc == 0) && (*stream_size > 0)){ + memcpy(tpm_bound_data->payloadData, *stream, tpm_bound_data->payloadDataSize); + *stream += tpm_bound_data->payloadDataSize; + *stream_size -= tpm_bound_data->payloadDataSize; + } + return rc; +} + +#if 0 +/* TPM_BoundData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + This structure serialization assumes that the payloadDataSize member indicates the size of + payloadData. +*/ + +TPM_RESULT TPM_BoundData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_BOUND_DATA *tpm_bound_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_BoundData_Store:\n"); + if (rc == 0) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_bound_data->ver)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_bound_data->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_bound_data->payloadData, + tpm_bound_data->payloadDataSize); + } + return rc; +} +#endif + +/* TPM_BoundData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the bound_data + sets pointers to NULL + calls TPM_BoundData_Init to set members back to default values + The bound_data itself is not freed +*/ + +void TPM_BoundData_Delete(TPM_BOUND_DATA *tpm_bound_data) +{ + printf(" TPM_BoundData_Delete:\n"); + if (tpm_bound_data != NULL) { + free(tpm_bound_data->payloadData); + TPM_BoundData_Init(tpm_bound_data); + } + return; +} + +/* + TPM_SEALED_DATA +*/ + +/* TPM_SealedData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SealedData_Init(TPM_SEALED_DATA *tpm_sealed_data) +{ + printf(" TPM_SealedData_Init:\n"); + tpm_sealed_data->payload = TPM_PT_SEAL; + TPM_Secret_Init(tpm_sealed_data->authData); + TPM_Secret_Init(tpm_sealed_data->tpmProof); + TPM_Digest_Init(tpm_sealed_data->storedDigest); + TPM_SizedBuffer_Init(&(tpm_sealed_data->data)); + return; +} + +/* TPM_SealedData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_SealedData_Init() + After use, call TPM_SealedData_Delete() to free memory +*/ + +TPM_RESULT TPM_SealedData_Load(TPM_SEALED_DATA *tpm_sealed_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SealedData_Load:\n"); + /* load payload */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_sealed_data->payload), stream, stream_size); + } + /* load authData */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_sealed_data->authData, stream, stream_size); + } + /* load tpmProof */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_sealed_data->tpmProof, stream, stream_size); + } + /* load storedDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_sealed_data->storedDigest, stream, stream_size); + } + /* load dataSize and data */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_sealed_data->data), stream, stream_size); + } + return rc; +} + +/* TPM_SealedData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_SealedData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SEALED_DATA *tpm_sealed_data) +{ + TPM_RESULT rc = 0; + printf(" TPM_SealedData_Store:\n"); + /* store payload */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_sealed_data->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + /* store authData */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_sealed_data->authData); + } + /* store tpmProof */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_sealed_data->tpmProof); + } + /* store storedDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_sealed_data->storedDigest); + } + /* store dataSize and data */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_sealed_data->data)); + } + return rc; +} + +/* TPM_SealedData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_SealedData_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_SealedData_Delete(TPM_SEALED_DATA *tpm_sealed_data) +{ + printf(" TPM_SealedData_Delete:\n"); + if (tpm_sealed_data != NULL) { + TPM_SizedBuffer_Delete(&(tpm_sealed_data->data)); + TPM_SealedData_Init(tpm_sealed_data); + } + return; +} + +/* TPM_SealedData_GenerateEncData() generates an enc_data structure by serializing the + TPM_SEALED_DATA structure and encrypting the result using the public key. +*/ + +TPM_RESULT TPM_SealedData_GenerateEncData(TPM_SIZED_BUFFER *enc_data, + const TPM_SEALED_DATA *tpm_sealed_data, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_SEALED_DATA serialization */ + + printf(" TPM_SealedData_GenerateEncData\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_SEALED_DATA */ + if (rc == 0) { + rc = TPM_SealedData_Store(&sbuffer, tpm_sealed_data); + } + /* encrypt the TPM_SEALED_DATA serialization buffer with the public key, and place + the result in the encData members */ + if (rc == 0) { + rc = TPM_RSAPublicEncryptSbuffer_Key(enc_data, &sbuffer, tpm_key); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_SealedData_DecryptEncData() decrypts the enc_data using the private key. The + result is deserialized and stored in the TPM_SEALED_DATA structure. + +*/ + +TPM_RESULT TPM_SealedData_DecryptEncData(TPM_SEALED_DATA *tpm_sealed_data, /* result */ + TPM_SIZED_BUFFER *enc_data, /* 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_SealedData_DecryptEncData:\n"); + /* allocate space for the decrypted data */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptMalloc(&decryptData, /* decrypted data */ + &decryptDataLength, /* actual size of decrypted data */ + enc_data->buffer, /* encrypted data */ + enc_data->size, /* encrypted data size */ + tpm_key); + } + /* load the TPM_SEALED_DATA structure from the decrypted data stream */ + if (rc == 0) { + /* use temporary variables, because TPM_SealedData_Load() moves the stream */ + stream = decryptData; + stream_size = decryptDataLength; + rc = TPM_SealedData_Load(tpm_sealed_data, &stream, &stream_size); + } + free(decryptData); /* @1 */ + return rc; +} + + +/* + TPM_STORED_DATA +*/ + +/* TPM_StoredData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StoredData_Init(TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + printf(" TPM_StoredData_Init: v%u\n", version); + if (version == 1) { + TPM_StructVer_Init(&(tpm_stored_data->ver)); + } + else { + ((TPM_STORED_DATA12 *)tpm_stored_data)->tag = TPM_TAG_STORED_DATA12; + ((TPM_STORED_DATA12 *)tpm_stored_data)->et = 0x0000; + } + TPM_SizedBuffer_Init(&(tpm_stored_data->sealInfo)); + TPM_SizedBuffer_Init(&(tpm_stored_data->encData)); + tpm_stored_data->tpm_seal_info = NULL; + return; +} + +/* TPM_StoredData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StoredData_Init() + After use, call TPM_StoredData_Delete() to free memory + + This function handles both TPM_STORED_DATA and TPM_STORED_DATA12 and returns the 'version'. +*/ + +TPM_RESULT TPM_StoredData_Load(TPM_STORED_DATA *tpm_stored_data, + unsigned int *version, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + /* Peek at the first byte to guess the version number. The data is verified later. + TPM_STORED_DATA is 01,01,00,00 TPM_STORED_DATA12 is 00,16,00,00 */ + if ((rc == 0) && (*stream_size > 0)) { + if (**stream == 0x01) { + *version = 1; + } + else { + *version = 2; + } + printf(" TPM_StoredData_Load: v%u\n", *version); + } + /* 1.1 load ver */ + if ((rc == 0) && (*version == 1)) { + rc = TPM_StructVer_Load(&(tpm_stored_data->ver), stream, stream_size); + } + /* 1.2 load tag */ + if ((rc == 0) && (*version != 1)) { + rc = TPM_Load16(&(((TPM_STORED_DATA12 *)tpm_stored_data)->tag), stream, stream_size); + } + /* 1.2 load et */ + if ((rc == 0) && (*version != 1)) { + rc = TPM_Load16(&(((TPM_STORED_DATA12 *)tpm_stored_data)->et), stream, stream_size); + } + /* check the TPM_STORED_DATA structure version */ + if ((rc == 0) && (*version == 1)) { + rc = TPM_StructVer_CheckVer(&(tpm_stored_data->ver)); + } + /* check the TPM_STORED_DATA12 structure tag */ + if ((rc == 0) && (*version != 1)) { + rc = TPM_StoredData_CheckTag((TPM_STORED_DATA12 *)tpm_stored_data); + } + /* load sealInfoSize and sealInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_stored_data->sealInfo), stream, stream_size); + } + /* load the TPM_PCR_INFO or TPM_PCR_INFO_LONG cache */ + if (rc == 0) { + if (*version == 1) { + rc = TPM_PCRInfo_CreateFromBuffer(&(tpm_stored_data->tpm_seal_info), + &(tpm_stored_data->sealInfo)); + } + else { + rc = TPM_PCRInfoLong_CreateFromBuffer + (&(((TPM_STORED_DATA12 *)tpm_stored_data)->tpm_seal_info_long), + &(tpm_stored_data->sealInfo)); + } + } + /* load encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_stored_data->encData), stream, stream_size); + } + return rc; +} + +/* TPM_StoredData_StoreClearData() serializes a TPM_STORED_DATA structure, excluding encData, + appending results to 'sbuffer'. + + Before serializing, it serializes tpm_seal_info to sealInfoSize and sealInfo. + + This function handles both TPM_STORED_DATA and TPM_STORED_DATA12. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StoredData_StoreClearData(TPM_STORE_BUFFER *sbuffer, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoredData_StoreClearData: v%u\n", version); + /* 1.1 store ver */ + if ((rc == 0) && (version == 1)) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_stored_data->ver)); + } + /* 1.2 store tag */ + if ((rc == 0) && (version != 1)) { + rc = TPM_Sbuffer_Append16(sbuffer, ((TPM_STORED_DATA12 *)tpm_stored_data)->tag); + } + /* 1.2 store et */ + if ((rc == 0) && (version != 1)) { + rc = TPM_Sbuffer_Append16(sbuffer, ((TPM_STORED_DATA12 *)tpm_stored_data)->et); + } + /* store sealInfoSize and sealInfo */ + if (rc == 0) { + /* copy cache to sealInfoSize and sealInfo */ + if (version == 1) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_stored_data->sealInfo), + tpm_stored_data->tpm_seal_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfo_Store); + } + else { + rc = TPM_SizedBuffer_SetStructure(&(tpm_stored_data->sealInfo), + tpm_stored_data->tpm_seal_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfoLong_Store); + } + } + /* copy sealInfoSize and sealInfo to sbuffer */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_stored_data->sealInfo)); + } + return rc; +} + +/* TPM_StoredData_Store() + + Before serializing, it serializes tpm_seal_info to sealInfoSize and sealInfo. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StoredData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoredData_Store: v%u\n", version); + if (rc == 0) { + rc = TPM_StoredData_StoreClearData(sbuffer, tpm_stored_data, version); + } + /* store encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_stored_data->encData)); + } + return rc; +} + +/* TPM_StoredData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_StoredData_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_StoredData_Delete(TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + printf(" TPM_StoredData_Delete: v%u\n", version); + if (tpm_stored_data != NULL) { + TPM_SizedBuffer_Delete(&(tpm_stored_data->sealInfo)); + TPM_SizedBuffer_Delete(&(tpm_stored_data->encData)); + if (version == 1) { + TPM_PCRInfo_Delete(tpm_stored_data->tpm_seal_info); + free(tpm_stored_data->tpm_seal_info); + } + else { + TPM_PCRInfoLong_Delete((TPM_PCR_INFO_LONG *)tpm_stored_data->tpm_seal_info); + free(tpm_stored_data->tpm_seal_info); + } + TPM_StoredData_Init(tpm_stored_data, version); + } + return; +} + +/* TPM_StoredData_CheckTag() verifies the tag and et members of a TPM_STORED_DATA12 structure + + */ + +TPM_RESULT TPM_StoredData_CheckTag(TPM_STORED_DATA12 *tpm_stored_data12) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoredData_CheckTag:\n"); + if (rc == 0) { + if (tpm_stored_data12->tag != TPM_TAG_STORED_DATA12) { + printf("TPM_StoredData_CheckTag: Error, tag expected %04x found %04hx\n", + TPM_TAG_STORED_DATA12, tpm_stored_data12->tag); + rc = TPM_BAD_VERSION; + } + } + return rc; +} + +/* TPM_StoredData_GenerateDigest() generates a TPM_DIGEST over the TPM_STORED_DATA structure + excluding the encDataSize and encData members. +*/ + +TPM_RESULT TPM_StoredData_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_STORED_DATA serialization */ + + printf(" TPM_StoredData_GenerateDigest:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_STORED_DATA excluding the encData fields */ + if (rc == 0) { + rc = TPM_StoredData_StoreClearData(&sbuffer, tpm_stored_data, version); + } + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + Processing Functions +*/ + +/* TPM_SealCryptCommon() rev 98 + + Handles the encrypt/decrypt actions common to TPM_Sealx and TPM_Unseal + + 'encrypt TRUE for encryption, FALSE for decryption + + The output o1 must be freed by the caller. +*/ + +static TPM_RESULT TPM_SealCryptCommon(BYTE **o1, /* freed by caller */ + TPM_ADIP_ENC_SCHEME adipEncScheme, + TPM_SIZED_BUFFER *inData, + TPM_AUTH_SESSION_DATA *auth_session_data, + TPM_NONCE nonceOdd) +{ + TPM_RESULT rc = 0; + BYTE *x1; /* XOR string, MGF1 output */ + TPM_DIGEST ctr; /* symmetric key algorithm CTR */ + + printf(" TPM_SealCryptCommon:\n"); + x1 = NULL; /* freed @1 */ + + /* allocate for the output o1 */ + if (rc == TPM_SUCCESS) { + rc = TPM_Malloc(o1, inData->size); /* freed by caller */ + } + if (rc == TPM_SUCCESS) { + TPM_PrintFourLimit(" TPM_SealCryptCommon: input data", inData->buffer, inData->size); + } + switch (adipEncScheme) { + case TPM_ET_XOR: + printf(" TPM_SealCryptCommon: TPM_ET_XOR\n"); + if (rc == TPM_SUCCESS) { + /* i. Use MGF1 to create string X1 of length sealedDataSize. The inputs to MGF1 are; + authLastnonceEven, nonceOdd, "XOR", and authHandle -> sharedSecret. The four + concatenated values form the Z value that is the seed for MFG1. */ + rc = TPM_MGF1_GenerateArray(&x1, /* MGF1 array */ + inData->size, /* MGF1 array length */ + + TPM_NONCE_SIZE + + TPM_NONCE_SIZE + + sizeof("XOR") -1 + + TPM_DIGEST_SIZE, /* seed length */ + + TPM_NONCE_SIZE, auth_session_data->nonceEven, + TPM_NONCE_SIZE, nonceOdd, + sizeof("XOR") -1, "XOR", + TPM_DIGEST_SIZE, auth_session_data->sharedSecret, + 0, NULL); + } + /* ii. Create o1 by XOR of d1 -> data and X1 */ + if (rc == TPM_SUCCESS) { + TPM_PrintFour(" TPM_SealCryptCommon: XOR key", x1); + TPM_XOR(*o1, inData->buffer, x1, inData->size); + } + break; + case TPM_ET_AES128_CTR: + printf(" TPM_SealCryptCommon: TPM_ET_AES128_CTR\n"); + /* i. Create o1 by encrypting d1 -> data using the algorithm indicated by inData -> + et */ + /* ii. Key is from authHandle -> sharedSecret */ + /* iii. IV is SHA-1 of (authLastNonceEven || nonceOdd) */ + if (rc == TPM_SUCCESS) { + rc = TPM_SHA1(ctr, + TPM_NONCE_SIZE, auth_session_data->nonceEven, + TPM_NONCE_SIZE, nonceOdd, + 0, NULL); + } + if (rc == TPM_SUCCESS) { + TPM_PrintFour(" TPM_SealCryptCommon: AES key", auth_session_data->sharedSecret); + TPM_PrintFour(" TPM_SealCryptCommon: CTR", ctr); + rc = TPM_SymmetricKeyData_CtrCrypt(*o1, /* output data */ + inData->buffer, /* input data */ + inData->size, /* data size */ + auth_session_data->sharedSecret, /* key */ + TPM_SECRET_SIZE, /* key size */ + ctr, /* CTR */ + TPM_DIGEST_SIZE); /* CTR size */ + } + break; + default: + printf("TPM_SealCryptCommon: Error, unsupported adipEncScheme %02x\n", adipEncScheme); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + if (rc == 0) { + TPM_PrintFour(" TPM_SealCryptCommon: output data", *o1); + + } + free(x1); /* @1 */ + return rc; +} + +/* 10.1 TPM_Seal rev 110 + + The SEAL operation allows software to explicitly state the future "trusted" configuration that + the platform must be in for the secret to be revealed. The SEAL operation also implicitly + includes the relevant platform configuration (PCR-values) when the SEAL operation was + performed. The SEAL operation uses the tpmProof value to BIND the blob to an individual TPM. + + TPM_Seal is used to encrypt private objects that can only be decrypted using TPM_Unseal. +*/ + +TPM_RESULT TPM_Process_Seal(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 can perform seal + operations. */ + TPM_ENCAUTH encAuth; /* The encrypted authorization data for the sealed data. */ + TPM_SIZED_BUFFER pcrInfo; /* The PCR selection information. The caller MAY use + TPM_PCR_INFO_LONG. */ + TPM_SIZED_BUFFER inData; /* The data to be sealed to the platform and any specified + PCRs */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle + authorization. Must be an OS_AP session for this + command. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest for inputs and keyHandle. HMAC + key: key.usageAuth. */ + + /* processing */ + 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_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + unsigned int v1PcrVersion = 1; /* pcrInfo version */ + TPM_STORED_DATA12 *s1_12; + TPM_PCR_INFO tpm_pcr_info; /* deserialized pcrInfo v1 */ + TPM_PCR_INFO_LONG tpm_pcr_info_long; /* deserialized pcrInfo v2 */ + unsigned char *stream; + uint32_t stream_size; + TPM_DIGEST a1Auth; + TPM_SEALED_DATA s2SealedData; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORED_DATA s1StoredData; /* Encrypted, integrity-protected data object that is the + result of the TPM_Seal operation. Returned as + SealedData */ + + printf("TPM_Process_Seal: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&pcrInfo); /* freed @1 */ + TPM_SizedBuffer_Init(&inData); /* freed @2 */ + TPM_StoredData_Init(&s1StoredData, v1PcrVersion); /* freed @3, default is v1 */ + TPM_PCRInfo_Init(&tpm_pcr_info); /* freed @4 */ + TPM_PCRInfoLong_Init(&tpm_pcr_info_long); /* freed @5 */ + TPM_SealedData_Init(&s2SealedData); /* freed @6 */ + s1_12 = (TPM_STORED_DATA12 *)&s1StoredData; /* to avoid casts */ + /* + 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 encAuth parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Seal: keyHandle %08x\n", keyHandle); + returnCode = TPM_Authdata_Load(encAuth, &command, ¶mSize); + } + /* get pcrInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&pcrInfo, &command, ¶mSize); + } + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Seal: Sealing %u bytes\n", inData.size); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Seal: 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 + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, using to encrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get keyHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + key, + NULL, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 2. If the inDataSize is 0 the TPM returns TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (inData.size == 0) { + printf("TPM_Process_Seal: Error, inDataSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 3. If the keyUsage field of the key indicated by keyHandle does not have the value + TPM_KEY_STORAGE, the TPM must return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_Seal: Error, key keyUsage %04hx must be TPM_KEY_STORAGE\n", + key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. If the keyHandle points to a migratable key then the TPM MUST return the error code + TPM_INVALID_KEY_USAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_Seal: Error, key keyFlags %08x indicates migratable\n", + key->keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Determine the version of pcrInfo */ + if (returnCode == TPM_SUCCESS) { + /* a. If pcrInfoSize is 0 */ + if (pcrInfo.size == 0) { + v1PcrVersion = 1; /* i. set V1 to 1 */ + } + else { /* b. Else */ + /* i. Point X1 as TPM_PCR_INFO_LONG structure to pcrInfo */ + /* ii. If X1 -> tag is TPM_TAG_PCR_INFO_LONG */ + if (htons(*(uint16_t *)(pcrInfo.buffer)) == TPM_TAG_PCR_INFO_LONG) { + v1PcrVersion = 2; /* (1) Set V1 to 2 */ + } + else { /* iii. Else */ + v1PcrVersion = 1; /* (1) Set V1 to 1 */ + } + } + /* 6. If V1 is 1 then */ + /* a. Create S1 a TPM_STORED_DATA structure */ + /* 7. else */ + /* a. Create S1 a TPM_STORED_DATA12 structure */ + /* b. Set S1 -> et to 0 */ + /* 8. Set S1 -> encDataSize to 0 */ + /* 9. Set S1 -> encData to all zeros */ + printf("TPM_Process_Seal: V%u\n", v1PcrVersion); + TPM_StoredData_Init(&s1StoredData, v1PcrVersion); + /* 10. Set S1 -> sealInfoSize to pcrInfoSize */ + /* NOTE This step is unnecessary. If pcrInfoSize is 0, sealInfoSize is already initialized + to 0. If pcrInfoSize is non-zero, sealInfoSize is the result of serialization of the + tpm_seal_info member, which is either a TPM_PCR_INFO or a TPM_PCR_INFO_LONG */ + } + /* 11. If pcrInfoSize is not 0 then */ + if ((returnCode == TPM_SUCCESS) && (pcrInfo.size != 0)) { + printf("TPM_Process_Seal: Creating PCR digest\n"); + /* assign the stream, so pcrInfo is not altered */ + stream = pcrInfo.buffer; + stream_size = pcrInfo.size; + /* a. if V1 is 1 then */ + if (v1PcrVersion == 1) { + /* i. Validate pcrInfo as a valid TPM_PCR_INFO structure, return TPM_BADINDEX on + error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfo_Load(&tpm_pcr_info, &stream, &stream_size); + if (returnCode != 0) { + returnCode = TPM_BADINDEX; + } + } + /* build the TPM_STORED_DATA S1 structure */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set S1 -> sealInfo -> pcrSelection to pcrInfo -> pcrSelection */ + returnCode = TPM_PCRInfo_CreateFromBuffer(&(s1StoredData.tpm_seal_info), &pcrInfo); + } + /* iii. Create h1 the composite hash of the PCR selected by pcrInfo -> pcrSelection */ + /* iv. Set S1 -> sealInfo -> digestAtCreation to h1 */ + /* NOTE hash directly to destination. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_PCRSelection_GenerateDigest(s1StoredData.tpm_seal_info->digestAtCreation, + &(tpm_pcr_info.pcrSelection), + tpm_state->tpm_stclear_data.PCRS); + } + /* v. Set S1 -> sealInfo -> digestAtRelease to pcrInfo -> digestAtRelease */ + /* NOTE digestAtRelease copied during TPM_PCRInfo_CreateFromBuffer() */ + } + /* b. else (v1 is 2) */ + else { + /* i. Validate pcrInfo as a valid TPM_PCR_INFO_LONG structure, return TPM_BADINDEX + on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoLong_Load(&tpm_pcr_info_long, &stream, &stream_size); + if (returnCode != 0) { + returnCode = TPM_BADINDEX; + } + } + /* build the TPM_STORED_DATA S1 structure */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set S1 -> sealInfo -> creationPCRSelection to pcrInfo -> creationPCRSelection + */ + /* iii. Set S1 -> sealInfo -> releasePCRSelection to pcrInfo -> releasePCRSelection + */ + /* iv. Set S1 -> sealInfo -> digestAtRelease to pcrInfo -> digestAtRelease */ + /* v. Set S1 -> sealInfo -> localityAtRelease to pcrInfo -> localityAtRelease */ + /* NOTE copied during TPM_PCRInfoLong_CreateFromBuffer() */ + returnCode = TPM_PCRInfoLong_CreateFromBuffer(&(s1_12->tpm_seal_info_long), + &pcrInfo); + } + if (returnCode == TPM_SUCCESS) { + /* vi. Create h2 the composite hash of the PCR selected by pcrInfo -> + creationPCRSelection */ + /* vii. Set S1 -> sealInfo -> digestAtCreation to h2 */ + /* NOTE hash directly to destination. */ + returnCode = + TPM_PCRSelection_GenerateDigest(s1_12->tpm_seal_info_long->digestAtCreation, + &(tpm_pcr_info_long.creationPCRSelection), + tpm_state->tpm_stclear_data.PCRS); + } + /* viii. Set S1 -> sealInfo -> localityAtCreation to TPM_STANY_FLAGS -> + localityModifier */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Locality_Set(&(s1_12->tpm_seal_info_long->localityAtCreation), + tpm_state->tpm_stany_flags.localityModifier); + } + } + } + /* 12. Create a1 by decrypting encAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + encAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 13. The TPM provides NO validation of a1. Well-known values (like all zeros) are valid and + possible. */ + /* 14. Create S2 a TPM_SEALED_DATA structure */ + if (returnCode == TPM_SUCCESS) { + /* a. Set S2 -> payload to TPM_PT_SEAL */ + /* NOTE: Done at TPM_SealedData_Init() */ + /* b. Set S2 -> tpmProof to TPM_PERMANENT_DATA -> tpmProof */ + TPM_Secret_Copy(s2SealedData.tpmProof, tpm_state->tpm_permanent_data.tpmProof); + /* c. Create h3 the SHA-1 of S1 */ + /* d. Set S2 -> storedDigest to h3 */ + returnCode = TPM_StoredData_GenerateDigest(s2SealedData.storedDigest, + &s1StoredData, v1PcrVersion); + } + if (returnCode == TPM_SUCCESS) { + /* e. Set S2 -> authData to a1 */ + TPM_Secret_Copy(s2SealedData.authData, a1Auth); + /* f. Set S2 -> dataSize to inDataSize */ + /* g. Set S2 -> data to inData */ + returnCode = TPM_SizedBuffer_Copy(&(s2SealedData.data), &inData); + } + /* 15. Validate that the size of S2 can be encrypted by the key pointed to by keyHandle, return + TPM_BAD_DATASIZE on error */ + /* 16. Create s3 the encryption of S2 using the key pointed to by keyHandle */ + /* 17. Set continueAuthSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 18. Set S1 -> encDataSize to the size of s3 */ + /* 19. Set S1 -> encData to s3 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SealedData_GenerateEncData(&(s1StoredData.encData), &s2SealedData, key); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Seal: 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; + /* 20. Return S1 as sealedData */ + returnCode = TPM_StoredData_Store(response, &s1StoredData, v1PcrVersion); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* 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); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&pcrInfo); /* @1 */ + TPM_SizedBuffer_Delete(&inData); /* @2 */ + TPM_StoredData_Delete(&s1StoredData, v1PcrVersion); /* @3 */ + TPM_PCRInfo_Delete(&tpm_pcr_info); /* @4 */ + TPM_PCRInfoLong_Delete(&tpm_pcr_info_long); /* @5 */ + TPM_SealedData_Delete(&s2SealedData); /* @6 */ + return rcf; +} + +/* 10.7 TPM_Sealx rev 110 + + The TPM_Sealx command works exactly like the TPM_Seal command with the additional requirement of + encryption for the inData parameter. This command also places in the sealed blob the information + that the TPM_Unseal also requires encryption. + + TPM_Sealx requires the use of 1.2 data structures. The actions are the same as TPM_Seal without + the checks for 1.1 data structure usage. +*/ + +TPM_RESULT TPM_Process_Sealx(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 can perform seal + operations. */ + TPM_ENCAUTH encAuth; /* The encrypted authorization data for the sealed data */ + TPM_SIZED_BUFFER pcrInfo; /* If 0 there are no PCR registers in use. pcrInfo MUST use + TPM_PCR_INFO_LONG */ + TPM_SIZED_BUFFER inData; /* The data to be sealed to the platform and any specified + PCRs */ + + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization. Must be an OSAP session for this command. + */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest for inputs and keyHandle. HMAC + key: key.usageAuth. */ + + /* processing */ + 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_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORED_DATA12 s1StoredData; /* Encrypted, integrity-protected data object that + is the result of the TPM_Seal operation. Returned + as SealedData */ + TPM_STORED_DATA *s1_11; /* 1.1 version to avoid casts */ + TPM_SEALED_DATA s2SealedData; + TPM_DIGEST a1Auth; + BYTE *o1DecryptedData; + + printf("TPM_Process_Sealx: Ordinal Entry\n"); + s1_11 = (TPM_STORED_DATA *)&s1StoredData; /* 1.1 version to avoid casts */ + TPM_SizedBuffer_Init(&pcrInfo); /* freed @1 */ + TPM_SizedBuffer_Init(&inData); /* freed @2 */ + TPM_StoredData_Init(s1_11, 2); /* freed @3 */ + TPM_SealedData_Init(&s2SealedData); /* freed @4 */ + o1DecryptedData = NULL; /* freed @5 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get encAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(encAuth, &command, ¶mSize); + } + /* get pcrInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&pcrInfo, &command, ¶mSize); + } + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: Sealing %u bytes\n", inData.size); + TPM_PrintFourLimit("TPM_Process_Sealx: Sealing data", inData.buffer, inData.size); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Sealx: 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 + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, using to encrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get keyHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + key, + NULL, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 2. If the inDataSize is 0 the TPM returns TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (inData.size == 0) { + printf("TPM_Process_Sealx: Error, inDataSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 3. If the keyUsage field of the key indicated by keyHandle does not have the value + TPM_KEY_STORAGE, the TPM must return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_Sealx: Error, key keyUsage %04hx must be TPM_KEY_STORAGE\n", + key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. If the keyHandle points to a migratable key then the TPM MUST return the error code + TPM_INVALID_KEY_USAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_Sealx: Error, key keyFlags %08x indicates migratable\n", + key->keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Create S1 a TPM_STORED_DATA12 structure */ + /* 6. Set S1 -> encDataSize to 0 */ + /* 7. Set S1 -> encData to all zeros */ + /* NOTE: Done by TPM_StoredData_Init() */ + /* 8. Set S1 -> sealInfoSize to pcrInfoSize */ + /* NOTE This step is unnecessary. If pcrInfoSize is 0, sealInfoSize is already initialized + to 0. If pcrInfoSize is non-zero, sealInfoSize is the result of serialization of the + tpm_seal_info member, which is a TPM_PCR_INFO_LONG */ + /* 9. If pcrInfoSize is not 0 then */ + if ((returnCode == TPM_SUCCESS) && (pcrInfo.size != 0)) { + printf("TPM_Process_Sealx: Setting sealInfo to pcrInfo\n"); + /* initializing the s -> TPM_PCR_INFO_LONG cache to the contents of pcrInfo */ + /* a. Validate pcrInfo as a valid TPM_PCR_INFO_LONG structure, return TPM_BADINDEX on + error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoLong_CreateFromBuffer(&(s1StoredData.tpm_seal_info_long), + &pcrInfo); + if (returnCode != TPM_SUCCESS) { + returnCode = TPM_BADINDEX; + } + } + /* b. Set S1 -> sealInfo -> creationPCRSelection to pcrInfo -> creationPCRSelection */ + /* c. Set S1 -> sealInfo -> releasePCRSelection to pcrInfo -> releasePCRSelection */ + /* d. Set S1 -> sealInfo -> digestAtRelease to pcrInfo -> digestAtRelease */ + /* e. Set S1 -> sealInfo -> localityAtRelease to pcrInfo -> localityAtRelease */ + /* NOTE copied during TPM_PCRInfoLong_CreateFromBuffer() */ + /* f. Create h2 the composite hash of the PCR selected by pcrInfo -> creationPCRSelection */ + /* g. Set S1 -> sealInfo -> digestAtCreation to h2 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_GenerateDigest + (s1StoredData.tpm_seal_info_long->digestAtCreation, + &(s1StoredData.tpm_seal_info_long->creationPCRSelection), + tpm_state->tpm_stclear_data.PCRS); + } + /* h. Set S1 -> sealInfo -> localityAtCreation to TPM_STANY_DATA -> localityModifier */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Locality_Set(&(s1StoredData.tpm_seal_info_long->localityAtCreation), + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* 10. Create S2 a TPM_SEALED_DATA structure */ + /* NOTE: Done at TPM_SealedData_Init() */ + /* 11.Create a1 by decrypting encAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: Decrypting encAuth\n"); + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, /* a1 even */ + NULL, /* a1 odd (2nd encAuth) */ + encAuth, /* encAuthEven */ + auth_session_data, + NULL, /* nonceOdd */ + NULL, /* encAuthOdd */ + FALSE); /* even and odd */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_Sealx: Decrypted Auth", a1Auth); + /* a. If authHandle indicates XOR encryption for the AuthData secrets */ + if (auth_session_data->adipEncScheme == TPM_ET_XOR) { + /* i. Set S1 -> et to TPM_ET_XOR || TPM_ET_KEY */ + /* (1) TPM_ET_KEY is added because TPM_Unseal uses zero as a special value indicating no + encryption. */ + s1StoredData.et = TPM_ET_XOR | TPM_ET_KEY; + } + /* b. Else */ + else { + /* i. Set S1 -> et to algorithm indicated by authHandle */ + s1StoredData.et = auth_session_data->adipEncScheme << 8; + } + } + /* 12. The TPM provides NO validation of a1. Well-known values (like all zeros) are valid and + possible. */ + /* 13. If authHandle indicates XOR encryption */ + /* a. Use MGF1 to create string X2 of length inDataSize. The inputs to MGF1 are; + authLastNonceEven, nonceOdd, "XOR", and authHandle -> sharedSecret. The four concatenated + values form the Z value that is the seed for MFG1. */ + /* b. Create o1 by XOR of inData and x2 */ + /* 14. Else */ + /* a. Create o1 by decrypting inData using the algorithm indicated by authHandle */ + /* b. Key is from authHandle -> sharedSecret */ + /* c. CTR is SHA-1 of (authLastNonceEven || nonceOdd) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: decrypting inData\n"); + returnCode = TPM_SealCryptCommon(&o1DecryptedData, /* freed by caller */ + auth_session_data->adipEncScheme, + &inData, + auth_session_data, + nonceOdd); + + } + /* 15. Create S2 a TPM_SEALED_DATA structure */ + if (returnCode == TPM_SUCCESS) { + /* a. Set S2 -> payload to TPM_PT_SEAL */ + /* NOTE: Done at TPM_SealedData_Init() */ + /* b. Set S2 -> tpmProof to TPM_PERMANENT_DATA -> tpmProof */ + TPM_Secret_Copy(s2SealedData.tpmProof, tpm_state->tpm_permanent_data.tpmProof); + /* c. Create h3 the SHA-1 of S1 */ + /* d. Set S2 -> storedDigest to h3 */ + returnCode = TPM_StoredData_GenerateDigest(s2SealedData.storedDigest, s1_11, 2); + } + /* e. Set S2 -> authData to a1 */ + if (returnCode == TPM_SUCCESS) { + TPM_Secret_Copy(s2SealedData.authData, a1Auth); + /* f. Set S2 -> dataSize to inDataSize */ + /* g. Set S2 -> data to o1 */ + returnCode = TPM_SizedBuffer_Set(&(s2SealedData.data), inData.size, o1DecryptedData); + } + /* 16. Validate that the size of S2 can be encrypted by the key pointed to by keyHandle, return + */ + /* TPM_BAD_DATASIZE on error */ + /* 17. Create s3 the encryption of S2 using the key pointed to by keyHandle */ + /* 18. Set continueAuthSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 19. Set S1 -> encDataSize to the size of s3 */ + /* 20. Set S1 -> encData to s3 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: Encrypting sealed data\n"); + returnCode = TPM_SealedData_GenerateEncData(&(s1StoredData.encData), &s2SealedData, key); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Sealx: 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; + /* 21. Return S1 as sealedData */ + returnCode = TPM_StoredData_Store(response, s1_11, 2); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* 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); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&pcrInfo); /* @1 */ + TPM_SizedBuffer_Delete(&inData); /* @2 */ + TPM_StoredData_Delete(s1_11, 2); /* @3 */ + TPM_SealedData_Delete(&s2SealedData); /* @4 */ + free(o1DecryptedData); /* @5 */ + return rcf; +} + +/* 10.2 TPM_Unseal rev 110 + + The TPM_Unseal operation will reveal TPM_Sealed data only if it was encrypted on this platform + and the current configuration (as defined by the named PCR contents) is the one named as + qualified to decrypt it. Internally, TPM_Unseal accepts a data blob generated by a TPM_Seal + operation. TPM_Unseal decrypts the structure internally, checks the integrity of the resulting + data, and checks that the PCR named has the value named during TPM_Seal. Additionally, the + caller must supply appropriate authorization data for blob and for the key that was used to seal + that data. + + If the integrity, platform configuration and authorization checks succeed, the sealed data is + returned to the caller; otherwise, an error is generated. +*/ + +TPM_RESULT TPM_Process_Unseal(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 parentHandle; /* Handle of a loaded key that can unseal the data. */ + TPM_STORED_DATA inData; /* The encrypted data generated by TPM_Seal. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parentHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and + parentHandle. HMAC key: parentKey.usageAuth. */ + TPM_AUTHHANDLE dataAuthHandle; /* The authorization handle used to authorize inData. */ + TPM_NONCE datanonceOdd; /* Nonce generated by system associated with + entityAuthHandle */ + TPM_BOOL continueDataSession = TRUE; /* Continue usage flag for dataAuthHandle. */ + TPM_AUTHDATA dataAuth; /* The authorization digest for the encrypted entity. HMAC + key: entity.usageAuth. */ + + /* processing */ + 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 dataAuthHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *data_auth_session_data = NULL; /* session data for dataAuthHandle + */ + TPM_SECRET *hmacKey; + TPM_SECRET *dataHmacKey; + unsigned int v1StoredDataVersion = 1; /* version of TPM_STORED_DATA + inData */ + TPM_KEY *parentKey; + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + TPM_SEALED_DATA d1SealedData; + TPM_DIGEST h1StoredDataDigest; + TPM_STORED_DATA12 *s2StoredData; + BYTE *o1Encrypted; /* For ADIP encryption */ + TPM_ADIP_ENC_SCHEME adipEncScheme; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + uint32_t secretSize = 0; /* Decrypted data that had been sealed */ + BYTE *secret = NULL; + + printf("TPM_Process_Unseal: Ordinal Entry\n"); + TPM_StoredData_Init(&inData, v1StoredDataVersion); /* freed @1, default is v1 */ + TPM_SealedData_Init(&d1SealedData); /* freed @2 */ + o1Encrypted = NULL; /* freed @3 */ + s2StoredData = (TPM_STORED_DATA12 *)&inData; /* inData when it's a TPM_STORED_DATA12 + structure */ + /* + get inputs + */ + /* get parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: parentHandle %08x\n", parentHandle); + returnCode = TPM_StoredData_Load(&inData, &v1StoredDataVersion, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: inData is v%u\n", v1StoredDataVersion); + } + /* 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_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, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_Unseal: authHandle %08x\n", authHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&dataAuthHandle, + &dataAuthHandleValid, + datanonceOdd, + &continueDataSession, + dataAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: dataAuthHandle %08x\n", dataAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Unseal: 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; + dataAuthHandleValid = FALSE; + } + /* + Processing + */ + /* Verify that parentHandle points to a valid key. Get the TPM_KEY associated with parentHandle + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to decrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get parentHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the first 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, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. The TPM MUST validate that parentAuth authorizes the use of the key in parentHandle, 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 */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* if there are no parent auth parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_Unseal: Error, parent key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 2. If the keyUsage field of the key indicated by parentHandle does not have the value + TPM_KEY_STORAGE, the TPM MUST return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_Unseal: Error, key keyUsage %04hx must be TPM_KEY_STORAGE\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. The TPM MUST check that the TPM_KEY_FLAGS -> Migratable flag has the value FALSE in the + key indicated by parentKeyHandle. If not, the TPM MUST return the error code + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_Unseal: Error, key keyFlags %08x indicates migratable\n", + parentKey->keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Determine the version of inData */ + /* a. If inData -> tag = TPM_TAG_STORED_DATA12 */ + /* i. Set V1 to 2 */ + /* ii. Map S2 a TPM_STORED_DATA12 structure to inData */ + /* b. Else If inData -> ver = 1.1 */ + /* i. Set V1 to 1 */ + /* ii. Map S2 a TPM_STORED_DATA structure to inData */ + /* c. Else */ + /* i. Return TPM_BAD_VERSION */ + /* NOTE: Done during TPM_StoredData_Load() */ + /* The extra indent of error checking is required because the next steps all return + TPM_NOTSEALED_BLOB on error */ + if (returnCode == TPM_SUCCESS) { + /* 5. Create d1 by decrypting S2 -> encData using the key pointed to by parentHandle */ + printf("TPM_Process_Unseal: Decrypting encData\n"); + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SealedData_DecryptEncData(&d1SealedData, /* TPM_SEALED_DATA */ + &(inData.encData), + parentKey); + } + /* 6. Validate d1 */ + /* a. d1 MUST be a TPM_SEALED_DATA structure */ + /* NOTE Done during TPM_SealedData_DecryptEncData() */ + /* b. d1 -> tpmProof MUST match TPM_PERMANENT_DATA -> tpmProof */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: Sealed data size %u\n", d1SealedData.data.size); + TPM_PrintFour("TPM_Process_Unseal: Sealed data", d1SealedData.data.buffer); + printf("TPM_Process_Unseal: Checking tpmProof\n"); + returnCode = TPM_Secret_Compare(d1SealedData.tpmProof, + tpm_state->tpm_permanent_data.tpmProof); + } + if (returnCode == TPM_SUCCESS) { + /* c. Set S2 -> encDataSize to 0 */ + /* d. Set S2 -> encData to all zeros */ + /* NOTE: This would be done at cleanup */ + TPM_SizedBuffer_Delete(&(inData.encData)); + /* e. Create h1 the SHA-1 of S2 */ + returnCode = TPM_StoredData_GenerateDigest(h1StoredDataDigest, + &inData, v1StoredDataVersion); + } + /* f. d1 -> storedDigest MUST match h1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: Checking storedDigest\n"); + returnCode = TPM_Digest_Compare(d1SealedData.storedDigest, h1StoredDataDigest); + } + /* g. d1 -> payload MUST be TPM_PT_SEAL */ + if (returnCode == TPM_SUCCESS) { + if (d1SealedData.payload != TPM_PT_SEAL) { + printf("TPM_Process_Unseal: Error, payload %02x not TPM_PT_SEAL\n", + d1SealedData.payload); + returnCode = TPM_NOTSEALED_BLOB; + } + } + /* h. Any failure MUST return TPM_NOTSEALED_BLOB */ + if (returnCode != TPM_SUCCESS) { + returnCode = TPM_NOTSEALED_BLOB; + } + } + /* 7. If S2 -> sealInfo is not 0 then */ + /* NOTE: Done by _CheckDigest() */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: Checking PCR digest\n"); + /* a. If V1 is 1 then */ + if (v1StoredDataVersion == 1) { + /* i. Validate that S2 -> pcrInfo is a valid TPM_PCR_INFO structure */ + /* NOTE: Done during TPM_StoredData_Load() */ + /* ii. Create h2 the composite hash of the PCR selected by S2 -> pcrInfo -> pcrSelection + */ + /* c. Compare h2 with S2 -> pcrInfo -> digestAtRelease, on mismatch return + TPM_WRONGPCRVALUE */ + returnCode = TPM_PCRInfo_CheckDigest(inData.tpm_seal_info, + tpm_state->tpm_stclear_data.PCRS); /* PCR array */ + } + /* b. If V1 is 2 then */ + else { + /* i. Validate that S2 -> pcrInfo is a valid TPM_PCR_INFO_LONG structure */ + /* NOTE: Done during TPM_StoredData_Load() */ + /* ii. Create h2 the composite hash of the PCR selected by S2 -> pcrInfo -> + releasePCRSelection */ + /* iii. Check that S2 -> pcrInfo -> localityAtRelease for TPM_STANY_DATA -> + localityModifier is TRUE */ + /* (1) For example if TPM_STANY_DATA -> localityModifier was 2 then S2 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* c. Compare h2 with S2 -> pcrInfo -> digestAtRelease, on mismatch return + TPM_WRONGPCRVALUE */ + returnCode = + TPM_PCRInfoLong_CheckDigest(s2StoredData->tpm_seal_info_long, + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* 8. The TPM MUST validate authorization to use d1 by checking that the HMAC calculation + using d1 -> authData as the shared secret matches the dataAuth. Return TPM_AUTHFAIL on + mismatch. */ + /* get the second session data */ + /* NOTE: While OSAP isn't specifically excluded, there is currently no way to set up an OSAP + session using TPM_SEALED_DATA as the entity */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&data_auth_session_data, + &dataHmacKey, + tpm_state, + dataAuthHandle, + TPM_PID_OIAP, /* currently require OIAP */ + 0, /* OSAP entity type */ + ordinal, + NULL, + &(d1SealedData.authData), /* OIAP */ + NULL); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Auth2data_Check(tpm_state, + *dataHmacKey, /* HMAC key */ + inParamDigest, + data_auth_session_data, /* authorization session */ + datanonceOdd, /* Nonce generated by system + associated with authHandle */ + continueDataSession, + dataAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + /* 9. If V1 is 2 and S2 -> et specifies encryption (i.e. is not all zeros) then */ + if ((v1StoredDataVersion == 2) && (s2StoredData->et != 0x0000)) { + /* a. If tag is not TPM_TAG_RQU_AUTH2_COMMAND, return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + if (tag != TPM_TAG_RQU_AUTH2_COMMAND) { + printf("TPM_Process_Unseal: Error, sealed with encryption but auth-1\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* b. Verify that the authHandle session type is TPM_PID_OSAP or TPM_PID_DSAP, return + TPM_BAD_MODE on error. */ + if (returnCode == TPM_SUCCESS) { + if ((auth_session_data->protocolID != TPM_PID_OSAP) && + (auth_session_data->protocolID != TPM_PID_DSAP)) { + printf("TPM_Process_Unseal: Error, sealed with encryption but OIAP\n"); + returnCode = TPM_BAD_MODE; + } + } + /* c. If MSB of S2 -> et is TPM_ET_XOR */ + /* i. Use MGF1 to create string X1 of length sealedDataSize. The inputs to MGF1 are; + authLastnonceEven, nonceOdd, "XOR", and authHandle -> sharedSecret. The four + concatenated values form the Z value that is the seed for MFG1. */ + /* d. Else */ + /* i. Create o1 by encrypting d1 -> data using the algorithm indicated by inData -> + et */ + /* ii. Key is from authHandle -> sharedSecret */ + /* iii. IV is SHA-1 of (authLastNonceEven || nonceOdd) */ + if (returnCode == TPM_SUCCESS) { + /* entity type MSB is ADIP encScheme */ + adipEncScheme = (s2StoredData->et >> 8) & 0x00ff; + printf("TPM_Process_Unseal: Encrypting the output, encScheme %02x\n", + adipEncScheme); + returnCode = TPM_SealCryptCommon(&o1Encrypted, + adipEncScheme, + &(d1SealedData.data), + auth_session_data, + nonceOdd); + secretSize = d1SealedData.data.size; + secret = o1Encrypted; + } + /* e. Set continueAuthSession to FALSE */ + continueAuthSession = FALSE; + } + /* 10. else */ + else { + printf("TPM_Process_Unseal: No output encryption\n"); + /* a. Set o1 to d1 -> data */ + secretSize = d1SealedData.data.size; + secret = d1SealedData.data.buffer; + } + } + /* 11. Set the return secret as o1 */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Unseal: 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 secretSize */ + returnCode = TPM_Sbuffer_Append32(response, secretSize); + } + if (returnCode == TPM_SUCCESS) { + /* return secret */ + returnCode = TPM_Sbuffer_Append(response, secret, secretSize); + /* 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_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *dataHmacKey, /* HMAC key */ + data_auth_session_data, + outParamDigest, + datanonceOdd, + continueDataSession); + } + /* 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)) || + !continueDataSession) && + dataAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, dataAuthHandle); + } + /* + cleanup + */ + TPM_StoredData_Delete(&inData, v1StoredDataVersion); /* @1 */ + TPM_SealedData_Delete(&d1SealedData); /* @2 */ + free(o1Encrypted); /* @3 */ + return rcf; +} + +/* 10.3 TPM_UnBind rev 87 + + TPM_UnBind takes the data blob that is the result of a Tspi_Data_Bind command and decrypts it + for export to the User. The caller must authorize the use of the key that will decrypt the + incoming blob. + + UnBind operates on a block-by-block basis, and has no notion of any relation between one block + and another. + + UnBind SHALL operate on a single block only. +*/ + +TPM_RESULT TPM_Process_UnBind(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform + UnBind operations. */ + TPM_SIZED_BUFFER inData; /* Encrypted blob to be decrypted */ + TPM_AUTHHANDLE authHandle; /* The 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 + handle */ + TPM_AUTHDATA privAuth; /* The authorization digest that authorizes the inputs and + use of keyHandle. HMAC key: key.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; /* for key */ + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + uint32_t decrypt_data_size; /* resulting decrypted data size */ + BYTE *decrypt_data = NULL; /* The resulting decrypted data. */ + unsigned char *stream; + uint32_t stream_size; + TPM_BOUND_DATA tpm_bound_data; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + size_t outDataSize = 0; /* The length of the returned decrypted data */ + BYTE *outData = NULL; /* The resulting decrypted data. */ + + printf("TPM_Process_UnBind: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inData); /* freed @1 */ + TPM_BoundData_Init(&tpm_bound_data); /* 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 areaToSignSize and areaToSign parameters */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_UnBind: keyHandle %08x\n", keyHandle); + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_UnBind: UnBinding %u bytes\n", inData.size); + } + /* 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, + privAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_UnBind: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. If the inDataSize is 0 the TPM returns TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (inData.size == 0) { + printf("TPM_Process_UnBind: Error, inDataSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + if (key->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_UnBind: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* 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, + key, + keyUsageAuth, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 2. Validate the authorization to use the key pointed to by keyHandle */ + 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, + privAuth); /* Authorization digest for input */ + } + /* 3. If the keyUsage field of the key referenced by keyHandle does not have the value + TPM_KEY_BIND or TPM_KEY_LEGACY, the TPM must return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((key->keyUsage != TPM_KEY_BIND) && (key->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_UnBind: Error, invalid keyUsage %04hx\n", (key->keyUsage)); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* Get the TPM_RSA_KEY_PARMS associated with key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, &(key->algorithmParms)); + } + /* 4. Decrypt the inData using the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_RSAPrivateDecryptMalloc(&decrypt_data, /* decrypted data, freed @2 */ + &decrypt_data_size, /* actual size of decrypted data + data */ + inData.buffer, + inData.size, + key); + } + if (returnCode == TPM_SUCCESS) { + /* 5. if (keyHandle -> encScheme does not equal TPM_ES_RSAESOAEP_SHA1_MGF1) and (keyHandle + -> keyUsage equals TPM_KEY_LEGACY), */ + if ((key->algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) && + (key->keyUsage == TPM_KEY_LEGACY)) { + printf("TPM_Process_UnBind: Legacy key\n"); + /* a. The payload does not have TPM specific markers to validate, so no consistency + check can be performed. */ + /* b. Set the output parameter outData to the value of the decrypted value of + inData. (Padding associated with the encryption wrapping of inData SHALL NOT be + returned.) */ + outData = decrypt_data; + /* c. Set the output parameter outDataSize to the size of outData, as deduced from the + decryption process. */ + outDataSize = decrypt_data_size; + } + /* 6. else */ + else { + printf("TPM_Process_UnBind: Payload is TPM_BOUND_DATA structure\n"); + /* a. Interpret the decrypted data under the assumption that it is a TPM_BOUND_DATA + structure, and validate that the payload type is TPM_PT_BIND */ + if (returnCode == TPM_SUCCESS) { + stream = decrypt_data; + stream_size = decrypt_data_size; + returnCode = TPM_BoundData_Load(&tpm_bound_data, + &stream, + &stream_size); + } + if (returnCode == TPM_SUCCESS) { + if (tpm_bound_data.payload != TPM_PT_BIND) { + printf("TPM_Process_UnBind: Error, " + "TPM_BOUND_DATA->payload %02x not TPM_PT_BIND\n", + tpm_bound_data.payload); + returnCode = TPM_INVALID_STRUCTURE; + } + } + /* b. Set the output parameter outData to the value of TPM_BOUND_DATA -> + payloadData. (Other parameters of TPM_BOUND_DATA SHALL NOT be returned. Padding + associated with the encryption wrapping of inData SHALL NOT be returned.) */ + if (returnCode == TPM_SUCCESS) { + outData = tpm_bound_data.payloadData; + /* c. Set the output parameter outDataSize to the size of outData, as deduced from + the decryption process and the interpretation of TPM_BOUND_DATA. */ + outDataSize = tpm_bound_data.payloadDataSize; + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_UnBind: 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; + /* 10. Return the computed outData */ + /* append outDataSize */ + returnCode = TPM_Sbuffer_Append32(response, outDataSize); + } + if (returnCode == TPM_SUCCESS) { + /* append outData */ + returnCode = TPM_Sbuffer_Append(response, outData, outDataSize); + /* 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, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inData); /* @1 */ + free(decrypt_data); /* @2 */ + TPM_BoundData_Delete(&tpm_bound_data); /* @3 */ + return rcf; +} + +/* 10.4 TPM_CreateWrapKey rev 114 + + The TPM_CreateWrapKey command both generates and creates a secure storage bundle for asymmetric + keys. + + The newly created key can be locked to a specific PCR value by specifying a set of PCR registers. +*/ + +TPM_RESULT TPM_Process_CreateWrapKey(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 parentHandle; /* Handle of a loaded key that can perform key wrapping. */ + TPM_ENCAUTH dataUsageAuth; /* Encrypted usage authorization data for the key. */ + TPM_ENCAUTH dataMigrationAuth; /* Encrypted migration authorization data for the + key.*/ + TPM_KEY keyInfo; /* Information about key to be created, pubkey.keyLength and + keyInfo.encData elements are 0. MAY be TPM_KEY12 */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parent key + authorization. Must be an OSAP session. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest that authorizes the use of the + public key in parentHandle. HMAC key: + parentKey.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *parentKey = NULL; /* the key specified by parentHandle */ + TPM_BOOL parentPCRStatus; + TPM_RSA_KEY_PARMS *keyInfoRSAParms = NULL; /* substructure of keyInfo */ + TPM_SECRET du1UsageAuth; + TPM_SECRET dm1MigrationAuth; + TPM_STORE_ASYMKEY *wrappedStoreAsymkey; /* substructure of wrappedKey */ + TPM_PCR_INFO wrappedPCRInfo; + int ver; /* TPM_KEY or TPM_KEY12 */ + + /* output parameters */ + TPM_KEY wrappedKey; /* The TPM_KEY structure which includes the public and + encrypted private key. MAY be TPM_KEY12 */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_CreateWrapKey: Ordinal Entry\n"); + TPM_Key_Init(&keyInfo); + TPM_Key_Init(&wrappedKey); + TPM_PCRInfo_Init(&wrappedPCRInfo); + /* + get inputs + */ + /* get parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get dataUsageAuth parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: parentHandle %08x\n", parentHandle); + returnCode = TPM_Authdata_Load(dataUsageAuth, &command, ¶mSize); + } + /* get dataMigrationAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(dataMigrationAuth, &command, ¶mSize); + } + /* get keyInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&keyInfo, &command, ¶mSize); /* freed @1 */ + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateWrapKey: 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 + */ + /* get the key corresponding to the parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, tpm_state, + parentHandle, + FALSE, /* not r/o, using to encrypt w/public key */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + NULL, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate the authorization to use the key pointed to by parentHandle. Return TPM_AUTHFAIL + on any error. */ + /* 2. Validate the session type for parentHandle is OSAP. */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateWrapKey: sharedSecret", auth_session_data->sharedSecret); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle + */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 3. If the TPM is not designed to create a key of the type requested in keyInfo, return the + error code TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: Checking key properties\n"); + returnCode = TPM_Key_CheckProperties(&ver, &keyInfo, 0, + tpm_state->tpm_permanent_flags.FIPS); + } + /* Get the TPM_RSA_KEY_PARMS associated with keyInfo */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: key parameters v = %d\n", ver); + returnCode = TPM_KeyParms_GetRSAKeyParms(&keyInfoRSAParms, &(keyInfo.algorithmParms)); + } + /* 4. Verify that parentHandle->keyUsage equals TPM_KEY_STORAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_CreateWrapKey: Error, parent keyUsage not TPM_KEY_STORAGE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. If parentHandle -> keyFlags -> migratable is TRUE and keyInfo -> keyFlags -> migratable is + FALSE then return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((parentKey->keyFlags & TPM_MIGRATABLE) && !(keyInfo.keyFlags & TPM_MIGRATABLE)) { + printf("TPM_Process_CreateWrapKey: Error, parent not migratable\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. Validate key parameters */ + /* a. keyInfo -> keyUsage MUST NOT be TPM_KEY_IDENTITY or TPM_KEY_AUTHCHANGE. If it is, return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((keyInfo.keyUsage == TPM_KEY_IDENTITY) || + (keyInfo.keyUsage == TPM_KEY_AUTHCHANGE)) { + printf("TPM_Process_CreateWrapKey: Error, Invalid key usage %04x\n", + keyInfo.keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* b. If keyInfo -> keyFlags -> migrateAuthority is TRUE then return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (keyInfo.keyFlags & TPM_MIGRATEAUTHORITY) { + printf("TPM_Process_CreateWrapKey: Error, Invalid key flags %08x\n", + keyInfo.keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 7. If TPM_PERMANENT_FLAGS -> FIPS is TRUE then + a. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS + b. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS + c. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return TPM_NOTFIPS + NOTE Done in step 3 TPM_Key_CheckProperties() + */ + /* 8. If keyInfo -> keyUsage equals TPM_KEY_STORAGE or TPM_KEY_MIGRATE + i. algorithmID MUST be TPM_ALG_RSA + ii. encScheme MUST be TPM_ES_RSAESOAEP_SHA1_MGF1 + iii. sigScheme MUST be TPM_SS_NONE + iv. key size MUST be 2048 + v. exponentSize MUST be 0 + NOTE Done in step 3 TPM_Key_CheckProperties() + */ + /* 9. Determine the version of key + a.If keyInfo -> ver is 1.1 + i. Set V1 to 1 + ii. Map wrappedKey to a TPM_KEY structure + iii. Validate all remaining TPM_KEY structures + b. Else if keyInfo -> tag is TPM_TAG_KEY12 + i. Set V1 to 2 + ii. Map wrappedKey to a TPM_KEY12 structure + iii. Validate all remaining TPM_KEY12 structures + NOTE Check done by TPM_Key_CheckProperties() + NOTE Map done by TPM_Key_GenerateRSA() + */ + /* 10..Create DU1 by decrypting dataUsageAuth according to the ADIP indicated by authHandle */ + /* 11. Create DM1 by decrypting dataMigrationAuth according to the ADIP indicated by + authHandle */ + if (returnCode == TPM_SUCCESS) { + TPM_AuthSessionData_Decrypt(du1UsageAuth, + dm1MigrationAuth, + dataUsageAuth, /* even encAuth */ + auth_session_data, + nonceOdd, + dataMigrationAuth, /* odd encAuth */ + TRUE); + } + /* 12. Set continueAuthSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 13. Generate asymmetric key according to algorithm information in keyInfo */ + /* 14. Fill in the wrappedKey structure with information from the newly generated key. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: Generating key\n"); + returnCode = TPM_Key_GenerateRSA(&wrappedKey, + tpm_state, + parentKey, + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + ver, + keyInfo.keyUsage, + keyInfo.keyFlags, + keyInfo.authDataUsage, /* TPM_AUTH_DATA_USAGE */ + &(keyInfo.algorithmParms), /* TPM_KEY_PARMS */ + keyInfo.tpm_pcr_info, /* TPM_PCR_INFO */ + keyInfo.tpm_pcr_info_long); /* TPM_PCR_INFO_LONG */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetStoreAsymkey(&wrappedStoreAsymkey, + &wrappedKey); + } + if (returnCode == TPM_SUCCESS) { + /* a. Set wrappedKey -> encData -> usageAuth to DU1 */ + TPM_Secret_Copy(wrappedStoreAsymkey->usageAuth, du1UsageAuth); + /* b. If the KeyFlags -> migratable bit is set to 1, the wrappedKey -> encData -> + migrationAuth SHALL contain the decrypted value from dataMigrationAuth. */ + if (wrappedKey.keyFlags & TPM_MIGRATABLE) { + TPM_Secret_Copy(wrappedStoreAsymkey->migrationAuth, dm1MigrationAuth); + } + /* c. If the KeyFlags -> migratable bit is set to 0, the wrappedKey -> encData -> + migrationAuth SHALL be set to the value tpmProof */ + else { + TPM_Secret_Copy(wrappedStoreAsymkey->migrationAuth, + tpm_state->tpm_permanent_data.tpmProof); + } + printf("TPM_Process_CreateWrapKey: wrappedKey.PCRInfoSize %d\n", wrappedKey.pcrInfo.size); + } + /* 15. If keyInfo->PCRInfoSize is non-zero. */ + /* a. If V1 is 1 */ + /* i. Set wrappedKey -> pcrInfo to a TPM_PCR_INFO structure using the pcrSelection to + indicate the PCR's in use */ + /* b. Else */ + /* i. Set wrappedKey -> pcrInfo to a TPM_PCR_INFO_LONG structure */ + /* c. Set wrappedKey -> pcrInfo to keyInfo -> pcrInfo */ + /* d. Set wrappedKey -> digestAtCreation to the TPM_COMPOSITE_HASH indicated by + creationPCRSelection */ + /* e. If V1 is 2 set wrappedKey -> localityAtCreation to TPM_STANY_DATA -> locality */ + /* NOTE Done by TPM_Key_GenerateRSA() */ + /* 16. Encrypt the private portions of the wrappedKey structure using the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GenerateEncData(&wrappedKey, parentKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateWrapKey: 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; + /* 17. Return the newly generated key in the wrappedKey parameter */ + returnCode = TPM_Key_Store(response, &wrappedKey); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* cleanup */ + TPM_Key_Delete(&keyInfo); /* @1 */ + TPM_Key_Delete(&wrappedKey); /* @2 */ + TPM_PCRInfo_Delete(&wrappedPCRInfo); /* @3 */ + return rcf; +} + +/* 27.8 TPM_LoadKey rev 114 + + Version 1.2 deprecates LoadKey due to the HMAC of the new keyhandle on return. The wrapping makes + use of the handle difficult in an environment where the TSS, or other management entity, is + changing the TPM handle to a virtual handle. + + Software using loadKey on a 1.2 TPM can have a collision with the returned handle as the 1.2 TPM + uses random values in the lower three bytes of the handle. All new software must use LoadKey2 to + allow management software the ability to manage the key handle. + + Before the TPM can use a key to either wrap, unwrap, bind, unbind, seal, unseal, sign or perform + any other action, it needs to be present in the TPM. The TPM_LoadKey function loads the key into + the TPM for further use. +*/ + +TPM_RESULT TPM_Process_LoadKey(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 parentHandle; /* TPM handle of parent key. */ + TPM_KEY *inKey; /* Incoming key structure, both encrypted private and clear + public portions. MAY be TPM_KEY12 */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parentHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = FALSE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and + parentHandle. HMAC key: parentKey.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_SECRET *hmacKey; + TPM_BOOL key_added = FALSE; /* key has been added to handle list */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY_HANDLE inKeyHandle; /* Internal TPM handle where decrypted key was loaded. */ + + printf("TPM_Process_LoadKey: Ordinal Entry\n"); + inKey = NULL; /* freed @1 */ + /* + get inputs + */ + /* get parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* Allocate space for inKey. The key cannot be a local variable, since it persists in key + storage after the command completes. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKey: parentHandle %08x\n", parentHandle); + returnCode = TPM_Malloc((unsigned char **)&inKey, sizeof(TPM_KEY)); /* freed @1 */ + } + /* get inKey parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_Key_Init(inKey); /* freed @2 */ + returnCode = TPM_Key_Load(inKey, &command, ¶mSize); /* freed @2 */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_LoadKey: inKey n", inKey->pubKey.buffer); + } + /* 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, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadKey: 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) { + returnCode = TPM_LoadKeyCommon(&inKeyHandle, /* output */ + &key_added, /* output */ + &hmacKey, /* output */ + &auth_session_data, /* output */ + tpm_state, + tag, + ordinal, + parentHandle, + inKey, + inParamDigest, + authHandle, /*uninitialized*/ + nonceOdd, + continueAuthSession, + parentAuth); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadKey: 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 the key handle */ + returnCode = TPM_Sbuffer_Append32(response, inKeyHandle); + /* 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, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + /* if there was a failure, delete inKey */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(inKey); /* @2 */ + free(inKey); /* @1 */ + if (key_added) { + /* if there was a failure and inKey was stored in the handle list, free the handle. + Ignore errors, since only one error code can be returned. */ + TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, inKeyHandle); + } + } + return rcf; +} + +/* 10.5 TPM_LoadKey2 rev 107 + + Before the TPM can use a key to either wrap, unwrap, unbind, seal, unseal, sign or perform any + other action, it needs to be present in the TPM. The TPM_LoadKey2 function loads the key into + the TPM for further use. + + The TPM assigns the key handle. The TPM always locates a loaded key by use of the handle. The + assumption is that the handle may change due to key management operations. It is the + responsibility of upper level software to maintain the mapping between handle and any label used + by external software. + + This command has the responsibility of enforcing restrictions on the use of keys. For example, + when attempting to load a STORAGE key it will be checked for the restrictions on a storage key + (2048 size etc.). + + The load command must maintain a record of whether any previous key in the key hierarchy was + bound to a PCR using parentPCRStatus. + + The flag parentPCRStatus enables the possibility of checking that a platform passed through some + particular state or states before finishing in the current state. A grandparent key could be + linked to state-1, a parent key could linked to state-2, and a child key could be linked to + state-3, for example. The use of the child key then indicates that the platform passed through + states 1 and 2 and is currently in state 3, in this example. TPM_Startup with stType == + TPM_ST_CLEAR indicates that the platform has been reset, so the platform has not passed through + the previous states. Hence keys with parentPCRStatus==TRUE must be unloaded if TPM_Startup is + issued with stType == TPM_ST_CLEAR. + + If a TPM_KEY structure has been decrypted AND the integrity test using "pubDataDigest" has passed + AND the key is non-migratory, the key must have been created by the TPM. So there is every reason + to believe that the key poses no security threat to the TPM. While there is no known attack from + a rogue migratory key, there is a desire to verify that a loaded migratory key is a real key, + arising from a general sense of unease about execution of arbitrary data as a key. Ideally a + consistency check would consist of an encrypt/decrypt cycle, but this may be expensive. For RSA + keys, it is therefore suggested that the consistency test consists of dividing the supposed RSA + product by the supposed RSA prime, and checking that there is no remainder. +*/ + +TPM_RESULT TPM_Process_LoadKey2(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 parentHandle; /* TPM handle of parent key. */ + TPM_KEY *inKey; /* Incoming key structure, both encrypted private and clear + public portions. MAY be TPM_KEY12 */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parentHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = FALSE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and + parentHandle. HMAC key: parentKey.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_SECRET *hmacKey; + TPM_BOOL key_added = FALSE; /* key has been added to handle list */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY_HANDLE inKeyHandle; /* Internal TPM handle where decrypted key was loaded. */ + + printf("TPM_Process_LoadKey2: Ordinal Entry\n"); + inKey = NULL; /* freed @1 */ + /* + get inputs + */ + /* get parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* Allocate space for inKey. The key cannot be a local variable, since it persists in key + storage after the command completes. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKey2: parentHandle %08x\n", parentHandle); + returnCode = TPM_Malloc((unsigned char **)&inKey, sizeof(TPM_KEY)); /* freed @1 */ + } + /* get inKey parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_Key_Init(inKey); /* freed @2 */ + returnCode = TPM_Key_Load(inKey, &command, ¶mSize); /* freed @2 */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_LoadKey2: inKey n", inKey->pubKey.buffer); + } + /* 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, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadKey2: 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) { + returnCode = TPM_LoadKeyCommon(&inKeyHandle, /* output */ + &key_added, /* output */ + &hmacKey, /* output */ + &auth_session_data, /* output */ + tpm_state, + tag, + ordinal, + parentHandle, + inKey, + inParamDigest, + authHandle, /* uninitialized */ + nonceOdd, + continueAuthSession, + parentAuth); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadKey2: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + /* In TPM_LoadKey2, the inKeyHandle is not part of the output HMAC */ + /* return the key handle */ + returnCode = TPM_Sbuffer_Append32(response, inKeyHandle); + } + /* 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, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + /* if there was a failure, delete inKey */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(inKey); /* @2 */ + free(inKey); /* @1 */ + if (key_added) { + /* if there was a failure and inKey was stored in the handle list, free the handle. + Ignore errors, since only one error code can be returned. */ + TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, inKeyHandle); + } + } + return rcf; +} + +/* TPM_LoadKeyCommon rev 114 + + Code common to TPM_LoadKey and TPM_LoadKey2. They differ only in whether the key handle is + included in the response HMAC calculation. +*/ + +static TPM_RESULT TPM_LoadKeyCommon(TPM_KEY_HANDLE *inKeyHandle, /* output */ + TPM_BOOL *key_added, /* output */ + TPM_SECRET **hmacKey, /* output */ + TPM_AUTH_SESSION_DATA **auth_session_data, /* output */ + tpm_state_t *tpm_state, + TPM_TAG tag, + TPM_COMMAND_CODE ordinal, + TPM_KEY_HANDLE parentHandle, + TPM_KEY *inKey, + TPM_DIGEST inParamDigest, + TPM_AUTHHANDLE authHandle, + TPM_NONCE nonceOdd, + TPM_BOOL continueAuthSession, + TPM_AUTHDATA parentAuth) +{ + TPM_RESULT rc = 0; + TPM_KEY *parentKey; /* the key specified by parentHandle */ + TPM_SECRET *parentUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_BOOL parentPCRUsage; + int ver; + + printf("TPM_LoadKeyCommon:\n"); + *key_added = FALSE; /* key has been added to handle list */ + /* Verify that parentHandle points to a valid key. Get the TPM_KEY associated with parentHandle + */ + if (rc == TPM_SUCCESS) { + rc = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to decrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* check TPM_AUTH_DATA_USAGE authDataUsage */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_LoadKeyCommon: Error, authorization required\n"); + rc = TPM_AUTHFAIL; + } + } + /* get parentHandle -> usageAuth */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + rc = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the session data */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + rc = TPM_AuthSessions_GetData(auth_session_data, + hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. Validate the command and the parameters using parentAuth and parentHandle -> usageAuth */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + rc = TPM_Authdata_Check(tpm_state, + **hmacKey, /* HMAC key */ + inParamDigest, + *auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* 2. If parentHandle -> keyUsage is NOT TPM_KEY_STORAGE return TPM_INVALID_KEYUSAGE */ + if (rc == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_LoadKeyCommon: Error, " + "parentHandle -> keyUsage should be TPM_KEY_STORAGE, is %04x\n", + parentKey->keyUsage); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* 3. If the TPM is not designed to operate on a key of the type specified by inKey, return the + error code TPM_BAD_KEY_PROPERTY. */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_CheckProperties(&ver, inKey, 0, tpm_state->tpm_permanent_flags.FIPS); + printf("TPM_LoadKeyCommon: key parameters v = %d\n", ver); + } + /* 4. The TPM MUST handle both TPM_KEY and TPM_KEY12 structures. + This step is done at TPM_Key_Load() + */ + /* 5. Decrypt the inKey -> privkey to obtain TPM_STORE_ASYMKEY structure using the key in + parentHandle. + */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_DecryptEncData(inKey, parentKey); + } + /* 6. Validate the integrity of inKey and decrypted TPM_STORE_ASYMKEY + a. Reproduce inKey -> TPM_STORE_ASYMKEY -> pubDataDigest using the fields of inKey, and check + that the reproduced value is the same as pubDataDigest + */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_CheckPubDataDigest(inKey); + } + /* 7. Validate the consistency of the key and it's key usage. */ + /* a. If inKey -> keyFlags -> migratable is TRUE, the TPM SHALL verify consistency of the public + and private components of the asymmetric key pair. If inKey -> keyFlags -> migratable is + FALSE, the TPM MAY verify consistency of the public and private components of the asymmetric + key pair. The consistency of an RSA key pair MAY be verified by dividing the supposed (P*Q) + product by a supposed prime and checking that there is no remainder. + + This step is done at TPM_Key_Load() + */ + /* b. If inKey -> keyUsage is TPM_KEY_IDENTITY, verify that inKey->keyFlags->migratable is + FALSE. If it is not, return TPM_INVALID_KEYUSAGE + */ + if (rc == TPM_SUCCESS) { + if ((inKey->keyUsage == TPM_KEY_IDENTITY) && + (inKey->keyFlags & TPM_MIGRATABLE)) { + printf("TPM_LoadKeyCommon: Error, identity key is migratable\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* c. If inKey -> keyUsage is TPM_KEY_AUTHCHANGE, return TPM_INVALID_KEYUSAGE */ + if (rc == TPM_SUCCESS) { + if (inKey->keyUsage == TPM_KEY_AUTHCHANGE) { + printf("TPM_LoadKeyCommon: Error, keyUsage is TPM_KEY_AUTHCHANGE\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* d. If inKey -> keyFlags -> migratable equals 0 then verify that TPM_STORE_ASYMKEY -> + migrationAuth equals TPM_PERMANENT_DATA -> tpmProof */ + if (rc == TPM_SUCCESS) { + if (!(inKey->keyFlags & TPM_MIGRATABLE)) { + rc = TPM_Secret_Compare(tpm_state->tpm_permanent_data.tpmProof, + inKey->tpm_store_asymkey->migrationAuth); + if (rc != 0) { + printf("TPM_LoadKeyCommon: Error, tpmProof mismatch\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + } + /* e. Validate the mix of encryption and signature schemes + f. If TPM_PERMANENT_FLAGS -> FIPS is TRUE then + i. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS + ii. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return + TPM_NOTFIPS + iii. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return + TPM_NOTFIPS + g. If inKey -> keyUsage is TPM_KEY_STORAGE or TPM_KEY_MIGRATE + i. algorithmID MUST be TPM_ALG_RSA + ii. Key size MUST be 2048 + iii. exponentSize MUST be 0 + iv. sigScheme MUST be TPM_SS_NONE + h. If inKey -> keyUsage is TPM_KEY_IDENTITY + i. algorithmID MUST be TPM_ALG_RSA + ii. Key size MUST be 2048 + iv. exponentSize MUST be 0 + iii. encScheme MUST be TPM_ES_NONE + NOTE Done in step 3. + */ + if (rc == TPM_SUCCESS) { + /* i. If the decrypted inKey -> pcrInfo is NULL, */ + /* i. The TPM MUST set the internal indicator to indicate that the key is not using any PCR + registers. */ + /* j. Else */ + /* i. The TPM MUST store pcrInfo in a manner that allows the TPM to calculate a composite + hash whenever the key will be in use */ + /* ii. The TPM MUST handle both version 1.1 TPM_PCR_INFO and 1.2 TPM_PCR_INFO_LONG + structures according to the type of TPM_KEY structure */ + /* (1) The TPM MUST validate the TPM_PCR_INFO or TPM_PCR_INFO_LONG structures for legal + values. However, the digestAtRelease and localityAtRelease are not validated for + authorization until use time.*/ + /* NOTE TPM_Key_Load() loads the TPM_PCR_INFO or TPM_PCR_INFO_LONG cache */ + } + /* 8. Perform any processing necessary to make TPM_STORE_ASYMKEY key available for + operations. */ + /* NOTE Done at TPM_Key_Load() */ + /* 9. Load key and key information into internal memory of the TPM. If insufficient memory + exists return error TPM_NOSPACE. */ + /* 10. Assign inKeyHandle according to internal TPM rules. */ + /* 11. Set InKeyHandle -> parentPCRStatus to parentHandle -> parentPCRStatus. */ + if (rc == TPM_SUCCESS) { + *inKeyHandle = 0; /* no preferred value */ + rc = TPM_KeyHandleEntries_AddKeyEntry(inKeyHandle, /* output */ + tpm_state->tpm_key_handle_entries, /* input */ + inKey, /* input */ + parentPCRStatus, + 0); /* keyControl */ + } + if (rc == TPM_SUCCESS) { + printf(" TPM_LoadKeyCommon: Loaded key handle %08x\n", *inKeyHandle); + /* remember that the handle has been added to handle list, so it can be deleted on error */ + *key_added = TRUE; + + } + /* 12. If parentHandle indicates it is using PCR registers then set inKeyHandle -> + parentPCRStatus to TRUE. */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_GetPCRUsage(&parentPCRUsage, parentKey, 0); + } + if (rc == TPM_SUCCESS) { + if (parentPCRUsage) { + rc = TPM_KeyHandleEntries_SetParentPCRStatus(tpm_state->tpm_key_handle_entries, + *inKeyHandle, TRUE); + } + } + return rc; +} + +/* 10.6 TPM_GetPubKey rev 102 + + The owner of a key may wish to obtain the public key value from a loaded key. This information + may have privacy concerns so the command must have authorization from the key owner. +*/ + +TPM_RESULT TPM_Process_GetPubKey(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; /* TPM handle of key. */ + TPM_AUTHHANDLE authHandle; /* The authorization 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 + handle */ + TPM_AUTHDATA keyAuth; /* Authorization HMAC key: key.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *keyUsageAuth; + TPM_STORE_BUFFER pubkeyStream; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + const unsigned char *pubkeyStreamBuffer; /* output */ + uint32_t pubkeyStreamLength; + + printf("TPM_Process_GetPubKey: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubkeyStream); /* freed @1 */ + /* + 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; + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetPubKey: keyHandle %08x\n", keyHandle); + } + /* 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_GetPubKey: 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 + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetPubKey: Key handle %08x\n", keyHandle); + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + TRUE, /* read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* 1. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* 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, + key, + keyUsageAuth, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + + + /* a. Validate the command parameters using keyHandle -> usageAuth, on error return + TPM_AUTHFAIL */ + 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 */ + } + /* 2. Else */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + /* a. Verify that keyHandle -> authDataUsage is TPM_NO_READ_PUBKEY_AUTH or TPM_AUTH_NEVER, + on error return TPM_AUTHFAIL */ +#ifdef TPM_V12 + if ((key->authDataUsage != TPM_NO_READ_PUBKEY_AUTH) && + (key->authDataUsage != TPM_AUTH_NEVER)) { + printf("TPM_Process_GetPubKey: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } +#else /* TPM 1.1 does not have TPM_NO_READ_PUBKEY_AUTH */ + if (key->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_GetPubKey: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } +#endif + } +#ifdef TPM_V12 /* TPM 1.1 does not have readSRKPub */ + if (returnCode == TPM_SUCCESS) { + /* 3. If keyHandle == TPM_KH_SRK then */ + if ((keyHandle == TPM_KH_SRK) && + /* a. If TPM_PERMANENT_FLAGS -> readSRKPub is FALSE then return TPM_INVALID_KEYHANDLE */ + !tpm_state->tpm_permanent_flags.readSRKPub) { + printf("TPM_Process_GetPubKey: " + "Error, keyHandle is TPM_KH_SRK and readSRKPub is FALSE\n"); + returnCode = TPM_INVALID_KEYHANDLE; + } + } +#endif + /* 4. If keyHandle -> pcrInfoSize is not 0 */ + /* a. If keyHandle -> keyFlags has pcrIgnoredOnRead set to FALSE */ + /* i. Create a digestAtRelease according to the specified PCR registers and compare + to keyHandle -> digestAtRelease and if a mismatch return TPM_WRONGPCRVAL */ + /* ii. If specified validate any locality requests */ + /* NOTE: Done at TPM_KeyHandleEntries_GetKey() */ + /* 5. Create a TPM_PUBKEY structure and return */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_StorePubkey(&pubkeyStream, /* output */ + &pubkeyStreamBuffer, /* output */ + &pubkeyStreamLength, /* output */ + key); /* input */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetPubKey: 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; + /* TPM_PUBKEY structure */ + returnCode = TPM_Sbuffer_Append(response, pubkeyStreamBuffer, pubkeyStreamLength); + /* 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); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubkeyStream); /* @1 */ + return rcf; +} |