/********************************************************************************/ /* */ /* 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 #include #include #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; }