diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 21:41:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 21:41:43 +0000 |
commit | 92cccad89d1c12b39165d5f0ed7ccd2d44965a1a (patch) | |
tree | f59a2764cd8c50959050a428bd8fc935138df750 /src/tpm12/tpm_cryptoh.c | |
parent | Initial commit. (diff) | |
download | libtpms-92cccad89d1c12b39165d5f0ed7ccd2d44965a1a.tar.xz libtpms-92cccad89d1c12b39165d5f0ed7ccd2d44965a1a.zip |
Adding upstream version 0.9.2.upstream/0.9.2upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tpm12/tpm_cryptoh.c')
-rw-r--r-- | src/tpm12/tpm_cryptoh.c | 5427 |
1 files changed, 5427 insertions, 0 deletions
diff --git a/src/tpm12/tpm_cryptoh.c b/src/tpm12/tpm_cryptoh.c new file mode 100644 index 0000000..36df6aa --- /dev/null +++ b/src/tpm12/tpm_cryptoh.c @@ -0,0 +1,5427 @@ +/********************************************************************************/ +/* */ +/* High Level Platform Independent Cryptography */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_cryptoh.c 4540 2011-04-07 18:51:34Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* Redistributions in binary form must reproduce the above copyright */ +/* notice, this list of conditions and the following disclaimer in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ +/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR */ +/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ +/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ +/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, */ +/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY */ +/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ +/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE */ +/* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/********************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "tpm_admin.h" +#include "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_memory.h" +#include "tpm_migration.h" +#include "tpm_nonce.h" +#include "tpm_key.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_store.h" +#include "tpm_ver.h" + +#include "tpm_cryptoh.h" + +/* local prototypes */ + +static TPM_RESULT TPM_SHA1_valist(TPM_DIGEST md, + uint32_t length0, unsigned char *buffer0, + va_list ap); +static TPM_RESULT TPM_HMAC_Generatevalist(TPM_HMAC hmac, + const TPM_SECRET key, + va_list ap); + +static TPM_RESULT TPM_SHA1CompleteCommon(TPM_DIGEST hashValue, + void **sha1_context, + TPM_SIZED_BUFFER *hashData); + +/* + TPM_SIGN_INFO +*/ + +/* TPM_SignInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SignInfo_Init(TPM_SIGN_INFO *tpm_sign_info) +{ + printf(" TPM_SignInfo_Init:\n"); + memset(tpm_sign_info->fixed, 0, TPM_SIGN_INFO_FIXED_SIZE); + TPM_Nonce_Init(tpm_sign_info->replay); + TPM_SizedBuffer_Init(&(tpm_sign_info->data)); + return; +} + +/* TPM_SignInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_SignInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SIGN_INFO *tpm_sign_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SignInfo_Store:\n"); + /* store the tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_SIGNINFO); + } + /* store the fixed */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_sign_info->fixed, TPM_SIGN_INFO_FIXED_SIZE); + } + /* store the replay */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_sign_info->replay); + } + /* store the dataLen and data */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_sign_info->data)); + } + if (rc == 0) { + const unsigned char *buffer; + uint32_t length; + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + TPM_PrintAll(" TPM_SignInfo_Store: Buffer", buffer, length); + } + return rc; +} + +/* TPM_SignInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the sign_info + sets pointers to NULL + calls TPM_SignInfo_Init to set members back to default values + The sign_info itself is not freed +*/ + +void TPM_SignInfo_Delete(TPM_SIGN_INFO *tpm_sign_info) +{ + printf(" TPM_SignInfo_Delete:\n"); + if (tpm_sign_info != NULL) { + TPM_SizedBuffer_Delete(&(tpm_sign_info->data)); + TPM_SignInfo_Init(tpm_sign_info); + } + return; +} + +/* + TPM_CERTIFY_INFO +*/ + +/* TPM_CertifyInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CertifyInfo_Init(TPM_CERTIFY_INFO *tpm_certify_info) +{ + printf(" TPM_CertifyInfo_Init:\n"); + TPM_StructVer_Init(&(tpm_certify_info->version)); + tpm_certify_info->keyUsage = TPM_KEY_UNINITIALIZED; + tpm_certify_info->keyFlags = 0; + tpm_certify_info->authDataUsage = TPM_AUTH_ALWAYS; + TPM_KeyParms_Init(&(tpm_certify_info->algorithmParms)); + TPM_Digest_Init(tpm_certify_info->pubkeyDigest); + TPM_Nonce_Init(tpm_certify_info->data); + tpm_certify_info->parentPCRStatus = TRUE; + TPM_SizedBuffer_Init(&(tpm_certify_info->pcrInfo)); + tpm_certify_info->tpm_pcr_info = NULL; + return; +} + +#if 0 +/* TPM_CertifyInfo_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CertifyInfo_Init() + After use, call TPM_CertifyInfo_Delete() to free memory + + NOTE: Never called. +*/ + +TPM_RESULT TPM_CertifyInfo_Load(TPM_CERTIFY_INFO *tpm_certify_info, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo_Load:\n"); + /* load version */ + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_certify_info->version), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_certify_info->version)); + } + /* load keyUsage */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_certify_info->keyUsage), stream, stream_size); + } + /* load keyFlags */ + if (rc == 0) { + rc = TPM_KeyFlags_Load(&(tpm_certify_info->keyFlags), stream, stream_size); + } + /* load authDataUsage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info->authDataUsage), stream, stream_size); + } + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_certify_info->algorithmParms), stream, stream_size); + } + /* load pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_certify_info->pubkeyDigest, stream, stream_size); + } + /* load data */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_certify_info->data, stream, stream_size); + } + /* load parentPCRStatus */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_certify_info->parentPCRStatus), stream, stream_size); + } + /* load pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_certify_info->pcrInfo), stream, stream_size); + } + /* set TPM_PCR_INFO tpm_pcr_info cache from pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfo_CreateFromBuffer(&(tpm_certify_info->tpm_pcr_info), + &(tpm_certify_info->pcrInfo)); + } + return rc; +} +#endif + +/* TPM_CertifyInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CertifyInfo_Store(TPM_STORE_BUFFER *sbuffer, + TPM_CERTIFY_INFO *tpm_certify_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo_Store:\n"); + /* store version */ + if (rc == 0) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_certify_info->version)); + } + /* store keyUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_certify_info->keyUsage); + } + /* store keyFlags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_certify_info->keyFlags); + } + /* store authDataUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info->authDataUsage), + sizeof(TPM_AUTH_DATA_USAGE)); + } + /* store algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_certify_info->algorithmParms)); + } + /* store pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_certify_info->pubkeyDigest); + } + /* store data */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_certify_info->data); + } + /* store parentPCRStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info->parentPCRStatus), + sizeof(TPM_BOOL)); + } + /* copy cache to pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_certify_info->pcrInfo), + tpm_certify_info->tpm_pcr_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfo_Store); + } + /* copy pcrInfo to sbuffer */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info->pcrInfo)); + } + return rc; +} + +/* TPM_CertifyInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CertifyInfo_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CertifyInfo_Delete(TPM_CERTIFY_INFO *tpm_certify_info) +{ + printf(" TPM_CertifyInfo_Delete:\n"); + if (tpm_certify_info != NULL) { + TPM_KeyParms_Delete(&(tpm_certify_info->algorithmParms)); + /* pcrInfo */ + TPM_SizedBuffer_Delete(&(tpm_certify_info->pcrInfo)); + /* pcr cache */ + TPM_PCRInfo_Delete(tpm_certify_info->tpm_pcr_info); + free(tpm_certify_info->tpm_pcr_info); + TPM_CertifyInfo_Init(tpm_certify_info); + } + return; +} + +/* TPM_CertifyInfo_Set() fills in tpm_certify_info with the information from the key pointed to be + tpm_key +*/ + +TPM_RESULT TPM_CertifyInfo_Set(TPM_CERTIFY_INFO *tpm_certify_info, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo_Set:\n"); + if (rc == 0) { + tpm_certify_info->keyUsage = tpm_key->keyUsage; + tpm_certify_info->keyFlags = tpm_key->keyFlags; + tpm_certify_info->authDataUsage = tpm_key->authDataUsage; + rc = TPM_KeyParms_Copy(&(tpm_certify_info->algorithmParms), + &(tpm_key->algorithmParms)); + } + /* pubkeyDigest SHALL be a digest of the value TPM_KEY -> pubKey -> key in a TPM_KEY + representation of the key to be certified */ + if (rc == 0) { + rc = TPM_SHA1(tpm_certify_info->pubkeyDigest, + tpm_key->pubKey.size, tpm_key->pubKey.buffer, + 0, NULL); + } + return rc; +} + +/* + TPM_CERTIFY_INFO2 +*/ + +/* TPM_CertifyInfo2_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CertifyInfo2_Init(TPM_CERTIFY_INFO2 *tpm_certify_info2) +{ + printf(" TPM_CertifyInfo2_Init:\n"); + tpm_certify_info2->fill = 0x00; + tpm_certify_info2->payloadType = TPM_PT_ASYM; + tpm_certify_info2->keyUsage = TPM_KEY_UNINITIALIZED; + tpm_certify_info2->keyFlags = 0; + tpm_certify_info2->authDataUsage = TPM_AUTH_ALWAYS; + TPM_KeyParms_Init(&(tpm_certify_info2->algorithmParms)); + TPM_Digest_Init(tpm_certify_info2->pubkeyDigest); + TPM_Nonce_Init(tpm_certify_info2->data); + tpm_certify_info2->parentPCRStatus = TRUE; + TPM_SizedBuffer_Init(&(tpm_certify_info2->pcrInfo)); + TPM_SizedBuffer_Init(&(tpm_certify_info2->migrationAuthority)); + tpm_certify_info2->tpm_pcr_info_short = NULL; + return; +} + +#if 0 +/* TPM_CertifyInfo2_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CertifyInfo2_Init() + After use, call TPM_CertifyInfo2_Delete() to free memory +*/ + +TPM_RESULT TPM_CertifyInfo2_Load(TPM_CERTIFY_INFO2 *tpm_certify_info2, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo2_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CERTIFY_INFO2, stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info2->fill), stream, stream_size); + } + /* check fill immediately to ease debugging */ + if (rc == 0) { + if (tpm_certify_info2->fill != 0x00) { + printf("TPM_CertifyInfo2_Load: Error checking fill %02x\n", tpm_certify_info2->fill); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load payloadType */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info2->payloadType), stream, stream_size); + } + /* load keyUsage */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_certify_info2->keyUsage), stream, stream_size); + } + /* load keyFlags */ + if (rc == 0) { + rc = TPM_KeyFlags_Load(&(tpm_certify_info2->keyFlags), stream, stream_size); + } + /* load authDataUsage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info2->authDataUsage), stream, stream_size); + } + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_certify_info2->algorithmParms), stream, stream_size); + } + /* load pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_certify_info2->pubkeyDigest, stream, stream_size); + } + /* load data */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_certify_info2->data, stream, stream_size); + } + /* load parentPCRStatus */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_certify_info2->parentPCRStatus), stream, stream_size); + } + /* load pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_certify_info2->pcrInfo), stream, stream_size); + } + /* set TPM_PCR_INFO2 tpm_pcr_info cache from pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfoShort_CreateFromBuffer(&(tpm_certify_info2->tpm_pcr_info_short), + &(tpm_certify_info2->pcrInfo)); + } + /* load migrationAuthority */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_certify_info2->migrationAuthority), stream, stream_size); + } + /* check migrationAuthority immediately to ease debugging */ + if (rc == 0) { + if ((tpm_certify_info2->migrationAuthority.buffer != NULL) && + (tpm_certify_info2->migrationAuthority.size != TPM_DIGEST_SIZE)) { + printf("TPM_CertifyInfo2_Load: Error checking migrationAuthority %p, %u\n", + tpm_certify_info2->migrationAuthority.buffer, + tpm_certify_info2->migrationAuthority.size); + rc = TPM_INVALID_STRUCTURE; + } + } + return rc; +} +#endif + +/* TPM_CertifyInfo2_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CertifyInfo2_Store(TPM_STORE_BUFFER *sbuffer, + TPM_CERTIFY_INFO2 *tpm_certify_info2) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo2_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CERTIFY_INFO2); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->fill), sizeof(BYTE)); + } + /* store payloadType */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->payloadType), + sizeof(TPM_PAYLOAD_TYPE)); + } + /* store keyUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_certify_info2->keyUsage); + } + /* store keyFlags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_certify_info2->keyFlags); + } + /* store authDataUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->authDataUsage), + sizeof(TPM_AUTH_DATA_USAGE)); + } + /* store algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_certify_info2->algorithmParms)); + } + /* store pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_certify_info2->pubkeyDigest); + } + /* store data */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_certify_info2->data); + } + /* store parentPCRStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->parentPCRStatus), + sizeof(TPM_BOOL)); + } + /* copy cache to pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_certify_info2->pcrInfo), + tpm_certify_info2->tpm_pcr_info_short, + (TPM_STORE_FUNCTION_T)TPM_PCRInfoShort_Store); + } + /* copy pcrInfo to sbuffer */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info2->pcrInfo)); + } + /* store migrationAuthority */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info2->migrationAuthority)); + } + return rc; +} + +/* TPM_CertifyInfo2_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CertifyInfo2_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CertifyInfo2_Delete(TPM_CERTIFY_INFO2 *tpm_certify_info2) +{ + printf(" TPM_CertifyInfo2_Delete:\n"); + if (tpm_certify_info2 != NULL) { + TPM_KeyParms_Delete(&(tpm_certify_info2->algorithmParms)); + /* pcrInfo */ + TPM_SizedBuffer_Delete(&(tpm_certify_info2->pcrInfo)); + /* pcr cache */ + TPM_PCRInfoShort_Delete(tpm_certify_info2->tpm_pcr_info_short); + free(tpm_certify_info2->tpm_pcr_info_short); + TPM_SizedBuffer_Delete(&(tpm_certify_info2->migrationAuthority)); + TPM_CertifyInfo2_Init(tpm_certify_info2); + } + return; +} + +/* TPM_CertifyInfo2_Set() fills in tpm_certify_info2 with the information from the key pointed to by + tpm_key. + +*/ + +TPM_RESULT TPM_CertifyInfo2_Set(TPM_CERTIFY_INFO2 *tpm_certify_info2, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_CertifyInfo_Set:\n"); + /* get the TPM_STORE_ASYMKEY object */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + tpm_certify_info2->payloadType = tpm_store_asymkey->payload; + tpm_certify_info2->keyUsage = tpm_key->keyUsage; + tpm_certify_info2->keyFlags = tpm_key->keyFlags; + tpm_certify_info2->authDataUsage = tpm_key->authDataUsage; + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + rc = TPM_KeyParms_Copy(&(tpm_certify_info2->algorithmParms), + &(tpm_key->algorithmParms)); + } + /* pubkeyDigest SHALL be a digest of the value TPM_KEY -> pubKey -> key in a TPM_KEY + representation of the key to be certified */ + if (rc == 0) { + rc = TPM_SHA1(tpm_certify_info2->pubkeyDigest, + tpm_key->pubKey.size, tpm_key->pubKey.buffer, + 0, NULL); + } + return rc; +} + +/* + TPM_SYMMETRIC_KEY +*/ + +/* TPM_SymmetricKey_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SymmetricKey_Init(TPM_SYMMETRIC_KEY *tpm_symmetric_key) +{ + printf(" TPM_SymmetricKey_Init:\n"); + tpm_symmetric_key->algId = 0; + tpm_symmetric_key->encScheme = TPM_ES_NONE; + tpm_symmetric_key->size = 0; + tpm_symmetric_key->data = NULL; + return; +} + +/* TPM_SymmetricKey_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_SymmetricKey_Init() + After use, call TPM_SymmetricKey_Delete() to free memory +*/ + +TPM_RESULT TPM_SymmetricKey_Load(TPM_SYMMETRIC_KEY *tpm_symmetric_key, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKey_Load:\n"); + /* load algId */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_symmetric_key->algId), stream, stream_size); + } + /* load encScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_symmetric_key->encScheme), stream, stream_size); + } + /* load size */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_symmetric_key->size), stream, stream_size); + } + /* allocate memory for the data */ + if ((rc == 0) && (tpm_symmetric_key->size > 0)) { + rc = TPM_Malloc(&(tpm_symmetric_key->data), tpm_symmetric_key->size); + } + /* load data */ + if ((rc == 0) && (tpm_symmetric_key->size > 0)) { + rc = TPM_Loadn(tpm_symmetric_key->data, tpm_symmetric_key->size, stream, stream_size); + } + return rc; +} + +/* TPM_SymmetricKey_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_SymmetricKey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY *tpm_symmetric_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKey_Store:\n"); + /* store algId */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_symmetric_key->algId); + } + /* store encScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key->encScheme); + } + /* NOTE: Cannot use TPM_SizedBuffer_Store since the first parameter is a uint16_t */ + /* store size */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key->size); + } + /* store data */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_symmetric_key->data, tpm_symmetric_key->size); + } + return rc; +} + +/* TPM_SymmetricKey_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_SymmetricKey_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_SymmetricKey_Delete(TPM_SYMMETRIC_KEY *tpm_symmetric_key) +{ + printf(" TPM_SymmetricKey_Delete:\n"); + if (tpm_symmetric_key != NULL) { + free(tpm_symmetric_key->data); + TPM_SymmetricKey_Init(tpm_symmetric_key); + } + return; +} + +/* TPM_SymmetricKeyData_EncryptSbuffer() encrypts 'sbuffer' to 'encrypt_data' + + Padding is included, so the output may be larger than the input. + + 'encrypt_data' must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_EncryptSbuffer(TPM_SIZED_BUFFER *encrypt_data, + TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_data) +{ + TPM_RESULT rc = 0; + const unsigned char *decrypt_data; /* serialization buffer */ + uint32_t decrypt_data_size; /* serialization size */ + + printf(" TPM_SymmetricKeyData_EncryptSbuffer:\n"); + if (rc == 0) { + /* get the serialization results */ + TPM_Sbuffer_Get(sbuffer, &decrypt_data, &decrypt_data_size); + /* platform dependent symmetric key encrypt */ + rc = TPM_SymmetricKeyData_Encrypt(&(encrypt_data->buffer), /* output, caller frees */ + &(encrypt_data->size), /* output */ + decrypt_data, /* input */ + decrypt_data_size, /* input */ + tpm_symmetric_key_data); + } + return rc; +} + +/* TPM_SymmetricKeyData_StreamCrypt() encrypts or decrypts 'data_in' to 'data_out ' + + It assumes that the size of data_out and data_in are equal, and that a stream cipher mode is + used. For the supported stream ciphers, encrypt and decrypt are equivalent, so no direction flag + is required. + + AES 128 with CTR or OFB modes are supported. For CTR mode, pad is the initial count. For OFB + mode, pad is the IV. +*/ + +TPM_RESULT TPM_SymmetricKeyData_StreamCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + TPM_ALGORITHM_ID algId, /* algorithm */ + TPM_ENC_SCHEME encScheme, /* mode */ + const unsigned char *symmetric_key, /* input */ + uint32_t symmetric_key_size, /* input */ + unsigned char *pad_in, /* input */ + uint32_t pad_in_size) /* input */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKeyData_StreamCrypt:\n"); + switch (algId) { + case TPM_ALG_AES128: + switch (encScheme) { + case TPM_ES_SYM_CTR: + rc = TPM_SymmetricKeyData_CtrCrypt(data_out, + data_in, + data_size, + symmetric_key, + symmetric_key_size, + pad_in, + pad_in_size); + break; + case TPM_ES_SYM_OFB: + rc = TPM_SymmetricKeyData_OfbCrypt(data_out, + data_in, + data_size, + symmetric_key, + symmetric_key_size, + pad_in, + pad_in_size); + break; + default: + printf("TPM_SymmetricKeyData_StreamCrypt: Error, bad AES128 encScheme %04x\n", + encScheme); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + break; + default: + printf("TPM_SymmetricKeyData_StreamCrypt: Error, bad algID %08x\n", algId); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + return rc; +} + +/* These functions perform high-level, platform independent functions. + They call the lower level, platform dependent crypto functions in + tpm_crypto.c +*/ + +/* TPM_SHA1Sbuffer() calculates the SHA-1 digest of a TPM_STORE_BUFFER. + + This is commonly used when calculating a digest on a serialized structure. Structures are + serialized to a TPM_STORE_BUFFER. + + The TPM_STORE_BUFFER is not deleted. +*/ + +TPM_RESULT TPM_SHA1Sbuffer(TPM_DIGEST tpm_digest, + TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_SHA1Sbuffer:\n"); + if (rc == 0) { + /* get the components of the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + TPM_PrintFour(" TPM_SHA1Sbuffer: input", buffer); + /* hash the serialized buffer to tpm_digest */ + rc = TPM_SHA1(tpm_digest, + length, buffer, + 0, NULL); + } + return rc; +} + +/* TPM_SHA1_GenerateStructure() generates a SHA-1 digest of a structure. It serializes the + structure and hashes the result. + + tpmStructure is the structure to be serialized + storeFunction is the serialization function for the structure +*/ + +TPM_RESULT TPM_SHA1_GenerateStructure(TPM_DIGEST tpm_digest, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + + printf(" TPM_SHA1_GenerateStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* Serialize the structure */ + if (rc == 0) { + rc = storeFunction(&sbuffer, tpmStructure); + } + /* hash the serialized buffer to tpm_hmac */ + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_SHA1_CheckStructure() generates a SHA-1 digest of a structure. It serializes the structure + and hashes the result. It compares the result to 'expected_digest' and returns 'error' on + mismatch. + + tpmStructure is the structure to be serialized + storeFunction is the serialization function for the structure +*/ + + + +TPM_RESULT TPM_SHA1_CheckStructure(TPM_DIGEST expected_digest, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction, + TPM_RESULT error) +{ + TPM_RESULT rc = 0; + TPM_DIGEST actual_digest; + + printf(" TPM_SHA1_CheckStructure:\n"); + /* hash the serialized buffer to tpm_digest */ + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(actual_digest, tpmStructure, storeFunction); + } + /* check the digests */ + if (rc == 0) { + rc = TPM_Digest_Compare(actual_digest, expected_digest); + if (rc != 0) { + rc = error; + } + } + return rc; +} + +/* TPM_SHA1() can be called directly to hash a list of streams. + + The ... arguments to be hashed are a list of the form + size_t length, unsigned char *buffer + terminated by a 0 length + */ + +TPM_RESULT TPM_SHA1(TPM_DIGEST md, ...) +{ + TPM_RESULT rc = 0; + va_list ap; + + printf(" TPM_SHA1:\n"); + va_start(ap, md); + rc = TPM_SHA1_valist(md, 0, NULL, ap); + va_end(ap); + return rc; +} + +/* TPM_SHA1_Check() digests the list of streams and compares the result to 'digest_expect' + */ + +TPM_RESULT TPM_SHA1_Check(TPM_DIGEST digest_expect, ...) +{ + TPM_RESULT rc = 0; + TPM_DIGEST digest_actual; + va_list ap; + + printf(" TPM_SHA1_Check:\n"); + if (rc == 0) { + va_start(ap, digest_expect); + rc = TPM_SHA1_valist(digest_actual, 0, NULL, ap); + va_end(ap); + } + if (rc == 0) { + rc = TPM_Digest_Compare(digest_expect, digest_actual); + } + return rc; +} + +/* TPM_SHA1_valist() is the internal function, called with the va_list already created. + + It is called from TPM_SHA1() to do a simple hash. Typically length0==0 and buffer0==NULL. + + It can also be called from the HMAC function to hash the variable number of input parameters. In + that case, the va_list for the text is already formed. length0 and buffer0 are used to input the + padded key. +*/ + +static TPM_RESULT TPM_SHA1_valist(TPM_DIGEST md, + uint32_t length0, unsigned char *buffer0, + va_list ap) +{ + TPM_RESULT rc = 0; + uint32_t length; + unsigned char *buffer; + void *context = NULL; /* platform dependent context */ + TPM_BOOL done = FALSE; + + printf(" TPM_SHA1_valist:\n"); + if (rc == 0) { + rc = TPM_SHA1InitCmd(&context); + } + if (rc == 0) { + if (length0 !=0) { /* optional first text block */ + printf(" TPM_SHA1_valist: Digesting %u bytes\n", length0); + rc = TPM_SHA1UpdateCmd(context, buffer0, length0); /* hash the buffer */ + } + } + while ((rc == 0) && !done) { + length = va_arg(ap, uint32_t); /* first vararg is the length */ + if (length != 0) { /* loop until a zero length argument terminates */ + buffer = va_arg(ap, unsigned char *); /* second vararg is the array */ + printf(" TPM_SHA1_valist: Digesting %u bytes\n", length); + rc = TPM_SHA1UpdateCmd(context, buffer, length); /* hash the buffer */ + } + else { + done = TRUE; + } + } + if (rc == 0) { + rc = TPM_SHA1FinalCmd(md, context); + } + if (rc == 0) { + TPM_PrintFour(" TPM_SHA1_valist: Digest", md); + } + /* call TPM_SHA1Delete even if there was an error */ + TPM_SHA1Delete(&context); + return rc; +} + +/* TPM_HMAC_GenerateSbuffer() calculates the HMAC digest of a TPM_STORE_BUFFER. + + This is commonly used when calculating an HMAC on a serialized structure. Structures are + serialized to a TPM_STORE_BUFFER. + + The TPM_STORE_BUFFER is not deleted. +*/ + +TPM_RESULT TPM_HMAC_GenerateSbuffer(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_HMAC_GenerateSbuffer:\n"); + if (rc == 0) { + /* get the components of the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* HMAC the serialized buffer to tpm_hmac */ + rc = TPM_HMAC_Generate(tpm_hmac, + hmac_key, + length, buffer, + 0, NULL); + } + return rc; +} + +/* TPM_HMAC_GenerateStructure() generates an HMAC of a structure. It serializes the structure and + HMAC's the result. + + hmacKey is the HMAC key + tpmStructure is the structure to be serialized + storeFunction is the serialization function for the structure +*/ + +TPM_RESULT TPM_HMAC_GenerateStructure(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + + printf(" TPM_HMAC_GenerateStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* Serialize the structure */ + if (rc == 0) { + rc = storeFunction(&sbuffer, tpmStructure); + } + /* hash the serialized buffer to tpm_hmac */ + if (rc == 0) { + rc = TPM_HMAC_GenerateSbuffer(tpm_hmac, hmac_key, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_HMAC_Generate() can be called directly to HMAC a list of streams. + + The ... arguments are a message list of the form + size_t length, unsigned char *buffer + terminated by a 0 length +*/ + +TPM_RESULT TPM_HMAC_Generate(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + ...) +{ + TPM_RESULT rc = 0; + va_list ap; + + printf(" TPM_HMAC_Generate:\n"); + va_start(ap, hmac_key); + rc = TPM_HMAC_Generatevalist(tpm_hmac, hmac_key, ap); + va_end(ap); + return rc; +} + +/* TPM_HMAC_Generatevalist() is the internal function, called with the va_list already created. + + It is called from TPM_HMAC_Generate() and TPM_HMAC_Check() with the va_list for the text already + formed. +*/ + +#define TPM_HMAC_BLOCK_SIZE 64 + +static TPM_RESULT TPM_HMAC_Generatevalist(TPM_HMAC tpm_hmac, + const TPM_SECRET key, + va_list ap) +{ + TPM_RESULT rc = 0; + unsigned char ipad[TPM_HMAC_BLOCK_SIZE]; + unsigned char opad[TPM_HMAC_BLOCK_SIZE]; + size_t i; + TPM_DIGEST inner_hash; + + printf(" TPM_HMAC_Generatevalist:\n"); + /* calculate key XOR ipad and key XOR opad */ + if (rc == 0) { + /* first part, key XOR pad */ + for (i = 0 ; i < TPM_AUTHDATA_SIZE ; i++) { + ipad[i] = key[i] ^ 0x36; /* magic numbers from RFC 2104 */ + opad[i] = key[i] ^ 0x5c; + } + /* second part, 0x00 XOR pad */ + memset(ipad + TPM_AUTHDATA_SIZE, 0x36, TPM_HMAC_BLOCK_SIZE - TPM_AUTHDATA_SIZE); + memset(opad + TPM_AUTHDATA_SIZE, 0x5c, TPM_HMAC_BLOCK_SIZE - TPM_AUTHDATA_SIZE); + /* calculate the inner hash, hash the key XOR ipad and the text */ + rc = TPM_SHA1_valist(inner_hash, + TPM_HMAC_BLOCK_SIZE, ipad, ap); + } + /* hash the key XOR opad and the previous hash */ + if (rc == 0) { + rc = TPM_SHA1(tpm_hmac, + TPM_HMAC_BLOCK_SIZE, opad, + TPM_DIGEST_SIZE, inner_hash, + 0, NULL); + } + if (rc == 0) { + TPM_PrintFour(" TPM_HMAC_Generatevalist: HMAC", tpm_hmac); + } + return rc; +} + +/* TPM_HMAC_CheckSbuffer() checks the HMAC of a TPM_STORE_BUFFER. + + This is commonly used when checking an HMAC on a serialized structure. Structures are serialized + to a TPM_STORE_BUFFER. + + The TPM_STORE_BUFFER is not deleted. +*/ + +TPM_RESULT TPM_HMAC_CheckSbuffer(TPM_BOOL *valid, /* result */ + TPM_HMAC expect, /* expected */ + const TPM_SECRET hmac_key, /* key */ + TPM_STORE_BUFFER *sbuffer) /* data stream */ +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_HMAC_CheckSbuffer:\n"); + if (rc == 0) { + /* get the components of the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* HMAC the serialized buffer to tpm_hmac */ + rc = TPM_HMAC_Check(valid, + expect, + hmac_key, + length, buffer, + 0, NULL); + } + return rc; +} + +/* TPM_HMAC_Check() can be called directly to check the HMAC of a list of streams. + + The ... arguments are a list of the form + size_t length, unsigned char *buffer + terminated by a 0 length + +*/ + +TPM_RESULT TPM_HMAC_Check(TPM_BOOL *valid, + TPM_HMAC expect, + const TPM_SECRET key, + ...) +{ + TPM_RESULT rc = 0; + va_list ap; + TPM_HMAC actual; + int result; + + printf(" TPM_HMAC_Check:\n"); + va_start(ap, key); + if (rc == 0) { + rc = TPM_HMAC_Generatevalist(actual, key, ap); + } + if (rc == 0) { + TPM_PrintFour(" TPM_HMAC_Check: Calculated", actual); + TPM_PrintFour(" TPM_HMAC_Check: Received ", expect); + result = memcmp(expect, actual, TPM_DIGEST_SIZE); + if (result == 0) { + *valid = TRUE; + } + else { + *valid = FALSE; + } + } + va_end(ap); + return rc; +} + +/* TPM_HMAC_CheckStructure() is a generic function that checks the integrity HMAC of a structure. + + hmacKey is the HMAC key + tpmStructure is the structure to be serialized + expect is the expected HMAC, a member of the structure + storeFunction is the serialization function for the structure + error is the failure return code + + The function saves a copy of the expected HMAC, and then NULL's the structure member. It + serializes the structure, generates an HMAC, and compares it to the expected value. + + As a side effect, the structure member is zeroed. +*/ + +TPM_RESULT TPM_HMAC_CheckStructure(const TPM_SECRET hmac_key, + void *tpmStructure, + TPM_HMAC expect, + TPM_STORE_FUNCTION_T storeFunction, + TPM_RESULT error) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + TPM_HMAC saveExpect; + TPM_BOOL valid; + + printf(" TPM_HMAC_CheckStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + if (rc == 0) { + TPM_Digest_Copy(saveExpect, expect); /* save the expected value */ + TPM_Digest_Init(expect); /* set value in structure to NULL */ + rc = storeFunction(&sbuffer, + tpmStructure); + } + /* verify the HMAC of the serialized structure */ + if (rc == 0) { + rc = TPM_HMAC_CheckSbuffer(&valid, /* result */ + saveExpect, /* expected */ + hmac_key, /* key */ + &sbuffer); /* data stream */ + } + if (rc == 0) { + if (!valid) { + printf("TPM_HMAC_CheckStructure: Error checking HMAC\n"); + rc = error; + } + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_XOR XOR's 'in1' and 'in2' of 'length', putting the result in 'out' + +*/ + +void TPM_XOR(unsigned char *out, + const unsigned char *in1, + const unsigned char *in2, + size_t length) +{ + size_t i; + + for (i = 0 ; i < length ; i++) { + out[i] = in1[i] ^ in2[i]; + } + return; +} + +/* TPM_MGF1() generates an MGF1 'array' of length 'arrayLen' from 'seed' of length 'seedlen' + + The openSSL DLL doesn't export MGF1 in Windows or Linux 1.0.0, so this version is created from + scratch. + + Algorithm and comments (not the code) from: + + PKCS #1: RSA Cryptography Specifications Version 2.1 B.2.1 MGF1 + + Prototype designed to be compatible with openSSL + + MGF1 is a Mask Generation Function based on a hash function. + + MGF1 (mgfSeed, maskLen) + + Options: + + Hash hash function (hLen denotes the length in octets of the hash + function output) + + Input: + + mgfSeed seed from which mask is generated, an octet string + maskLen intended length in octets of the mask, at most 2^32(hLen) + + Output: + mask mask, an octet string of length l; or "mask too long" + + Error: "mask too long' +*/ + +TPM_RESULT TPM_MGF1(unsigned char *mask, + uint32_t maskLen, + const unsigned char *mgfSeed, + uint32_t mgfSeedlen) +{ + TPM_RESULT rc = 0; + unsigned char counter[4]; /* 4 octets */ + uint32_t count; /* counter as an integral type */ + uint32_t outLen; + TPM_DIGEST lastDigest; + + printf(" TPM_MGF1: Output length %u\n", maskLen); + if (rc == 0) { + /* this is possible with arrayLen on a 64 bit architecture, comment to quiet beam */ + if ((maskLen / TPM_DIGEST_SIZE) > 0xffffffff) { /*constant condition*/ + printf(" TPM_MGF1: Error (fatal), Output length too large for 32 bit counter\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* 1.If l > 2^32(hLen), output "mask too long" and stop. */ + /* NOTE Checked by caller */ + /* 2. Let T be the empty octet string. */ + /* 3. For counter from 0 to [masklen/hLen] - 1, do the following: */ + for (count = 0, outLen = 0 ; (rc == 0) && (outLen < maskLen) ; count++) { + /* a. Convert counter to an octet string C of length 4 octets - see Section 4.1 */ + /* C = I2OSP(counter, 4) NOTE Basically big endian */ + uint32_t count_n = htonl(count); + memcpy(counter, &count_n, 4); + /* b.Concatenate the hash of the seed mgfSeed and C to the octet string T: */ + /* T = T || Hash (mgfSeed || C) */ + /* If the entire digest is needed for the mask */ + if ((outLen + TPM_DIGEST_SIZE) < maskLen) { + rc = TPM_SHA1(mask + outLen, + mgfSeedlen, mgfSeed, + 4, counter, + 0, NULL); + outLen += TPM_DIGEST_SIZE; + } + /* if the mask is not modulo TPM_DIGEST_SIZE, only part of the final digest is needed */ + else { + /* hash to a temporary digest variable */ + rc = TPM_SHA1(lastDigest, + mgfSeedlen, mgfSeed, + 4, counter, + 0, NULL); + /* copy what's needed */ + memcpy(mask + outLen, lastDigest, maskLen - outLen); + outLen = maskLen; /* outLen = outLen + maskLen - outLen */ + } + } + /* 4.Output the leading l octets of T as the octet string mask. */ + return rc; +} + +/* TPM_MGF1_GenerateArray() generates an array of length arrayLen using the varargs as the seed. + + Since the seed is a known length, it is passed in rather that extracted from the varargs. If the + seed length turns out to be wrong once the varargs are parsed, TPM_FAIL is returned. + + 'array' must be freed by the caller. +*/ + +TPM_RESULT TPM_MGF1_GenerateArray(unsigned char **array, + uint32_t arrayLen, + uint32_t seedLen, + ...) +{ + TPM_RESULT rc = 0; + va_list ap; + unsigned char *seed; /* constructed MGF1 seed */ + size_t vaLength; /* next seed segment length */ + unsigned char *vaBuffer; /* next seed segment buffer */ + uint32_t seedLeft; /* remaining seed bytes required */ + unsigned char *seedBuffer; /* running pointer to the seed array */ + TPM_BOOL done = FALSE; /* done when a vaLength == 0 is reached */ + + printf(" TPM_MGF1_GenerateArray: arrayLen %u seedLen %u\n", arrayLen, seedLen); + seed = NULL; /* freed @1 */ + *array = NULL; /* freed by caller */ + va_start(ap, seedLen); + /* allocate temporary memory for the seed */ + if (rc == 0) { + rc = TPM_Malloc(&seed, seedLen); + seedBuffer = seed; + seedLeft = seedLen; + } + /* construct the seed */ + while ((rc == 0) && !done) { + vaLength = (size_t)va_arg(ap, uint32_t); /* first vararg is the length */ + if (vaLength != 0) { /* loop until a zero length argument terminates */ + if (rc == 0) { + printf(" TPM_MGF1_GenerateArray: Appending %lu bytes\n", (unsigned long)vaLength); + if (vaLength > seedLeft) { + printf("TPM_MGF1_GenerateArray: Error (fatal), seedLen too small\n"); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + if (rc == 0) { + vaBuffer = va_arg(ap, unsigned char *); /* second vararg is the array */ + memcpy(seedBuffer, vaBuffer, vaLength); + seedBuffer += vaLength; + seedLeft-= vaLength; + } + } + else { + done = TRUE; + if (seedLeft != 0) { + printf("TPM_MGF1_GenerateArray: Error (fatal), seedLen too large by %u\n", + seedLeft); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + } + /* allocate memory for the array */ + if (rc == 0) { + rc = TPM_Malloc(array, arrayLen); + } + /* generate the MGF1 array */ + if (rc == 0) { + TPM_MGF1(*array, + arrayLen, + seed, + seedLen); + TPM_PrintFour(" TPM_MGF1_GenerateArray: MGF1", *array); + } + va_end(ap); + free(seed); /* @1 */ + return rc; +} + +/* TPM_bn2binMalloc() allocates a buffer 'bin' and loads it from 'bn'. + 'bytes' is set to the allocated size of 'bin'. + + If padBytes is non-zero, 'bin' is padded with leading zeros if necessary, so that 'bytes' will + equal 'padBytes'. This is used when TPM data structures expect a fixed length while the crypto + library 'bn to bin' function might truncates leading zeros. + + '*bin' must be freed by the caller +*/ + +TPM_RESULT TPM_bn2binMalloc(unsigned char **bin, /* freed by caller */ + unsigned int *bytes, + TPM_BIGNUM bn, + uint32_t padBytes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_bn2binMalloc: padBytes %u\n", padBytes); + /* number of bytes required in the bin array */ + if (rc == 0) { + rc = TPM_BN_num_bytes(bytes, bn); + } + /* calculate the array size to malloc */ + if (rc == 0) { + /* padBytes 0 says that no padding is required */ + if (padBytes == 0) { + padBytes = *bytes; /* setting equal yields no padding */ + } + /* if the array with padding is still less than the number of bytes required by the bignum, + this function fails */ + if (padBytes < *bytes) { + printf("TPM_bn2binMalloc: Error, " + "padBytes %u less than BN bytes %u\n", padBytes, *bytes); + rc = TPM_SIZE; + } + /* log if padding is occurring */ + if (padBytes != *bytes) { + printf(" TPM_bn2binMalloc: padBytes %u bytes %u\n", padBytes, *bytes); + } + } + /* allocate for the padded array */ + if (rc == 0) { + rc = TPM_Malloc(bin, padBytes); + *bytes = padBytes; + } + /* call the bignum to bin conversion */ + if (rc == 0) { + rc = TPM_bn2binArray(*bin, padBytes, bn); + } + return rc; +} + +/* TPM_bn2binArray() loads the array 'bin' of size 'bytes' from 'bn' + + The data from 'bn' is right justified and zero padded. +*/ + +TPM_RESULT TPM_bn2binArray(unsigned char *bin, + unsigned int bytes, + TPM_BIGNUM bn) +{ + TPM_RESULT rc = 0; + unsigned int numBytes; + + printf(" TPM_bn2binArray: size %u\n", bytes); + if (rc == 0) { + /* zero pad */ + memset(bin, 0, bytes); + /* bytes required for the bignum */ + rc = TPM_BN_num_bytes(&numBytes, bn); + } + /* if the array is less than the number of bytes required by the bignum, this function fails */ + if (rc == 0) { + printf(" TPM_bn2binArray: numBytes in bignum %u\n", numBytes); + if (numBytes > bytes) { + printf("TPM_bn2binArray: Error, " + "BN bytes %u greater than array bytes %u\n", numBytes, bytes); + rc = TPM_SIZE; + } + } + if (rc == 0) { + /* if there are bytes in the bignum (it is not zero) */ + if (numBytes > 0) { + rc = TPM_bn2bin(bin + bytes - numBytes, /* store right justified */ + bn); + } + } + return rc; +} + +/* TPM_2bin2bn() converts two byte arrays to a positive BIGNUM. + + The two byte arrays are concatenated. The concatenation is used to create the BIGNUM. + + bignum must be freed by the caller. +*/ + +TPM_RESULT TPM_2bin2bn(TPM_BIGNUM *bignum_in, /* freed by caller */ + const unsigned char *bin0, uint32_t size0, + const unsigned char *bin1, uint32_t size1) +{ + TPM_RESULT rc = 0; /* TPM return code */ + TPM_STORE_BUFFER sBuffer; /* used of >1 element or first element is negative */ + const unsigned char *buffer; + uint32_t size; + + printf(" TPM_bin2bn:\n"); + TPM_Sbuffer_Init(&sBuffer); /* freed @1 */ + /* append the first element */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(&sBuffer, bin0, size0); + } + /* append the next element */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(&sBuffer, bin1, size1); + } + /* create the BIGNUM from the array */ + if (rc == 0) { + TPM_Sbuffer_Get(&sBuffer, &buffer, &size); + /* create the BIGNUM */ + rc = TPM_bin2bn(bignum_in, buffer, size); /* freed by caller */ + } + TPM_Sbuffer_Delete(&sBuffer); /* @1 */ + return rc; +} + +/* TPM_RSAPrivateDecryptMalloc() allocates a buffer 'decrypt_data' of size 'decrypt_data_size' + and then calls TPM_RSAPrivateDecryptH(). +*/ + +TPM_RESULT TPM_RSAPrivateDecryptMalloc(unsigned char **decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + unsigned char *encrypt_data, + uint32_t encrypt_data_size, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + /* allocate space for the decrypted blob */ + printf(" TPM_RSAPrivateDecryptMalloc: Return max data size %u bytes\n", + tpm_key->pubKey.size); + if (rc == 0) { + rc = TPM_Malloc(decrypt_data, tpm_key->pubKey.size); + } + if (rc == 0) { + rc = TPM_RSAPrivateDecryptH(*decrypt_data, + decrypt_data_length, + tpm_key->pubKey.size, + encrypt_data, + encrypt_data_size, + tpm_key); + } + return rc; +} + +/* TPM_RSAPrivateDecryptH() decrypts 'encrypt_data' using the private key in + 'tpm_key' and 'decrypt_data_length' bytes are moved to 'decrypt_data'. + + 'decrypt_data_length' is at most 'decrypt_data_size'. +*/ + +TPM_RESULT TPM_RSAPrivateDecryptH(unsigned char *decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + uint32_t decrypt_data_size, /* size of decrypt_data buffer */ + unsigned char *encrypt_data, + uint32_t encrypt_data_size, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + unsigned char *darr; /* private exponent */ + uint32_t dbytes; + + printf(" TPM_RSAPrivateDecryptH: Data size %u bytes\n", encrypt_data_size); + TPM_PrintFourLimit(" TPM_RSAPrivateDecryptH: Encrypt data", encrypt_data, encrypt_data_size); + if (rc == 0) { + if (tpm_key == NULL) { + printf("TPM_RSAPrivateDecryptH: Error, NULL key\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* extract the public key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + /* extract the private key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPrivateKey(&dbytes, &darr, tpm_key); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + /* check the key size vs the data size */ + if (rc == 0) { + if (encrypt_data_size > nbytes) { + printf("TPM_RSAPrivateDecryptH: Error, data size too long for key size %u bytes\n", + nbytes); + rc = TPM_BAD_DATASIZE; + } + } + if (rc == 0) { + /* debug printing */ + printf(" TPM_RSAPrivateDecryptH: Public key length %u\n", nbytes); + printf(" TPM_RSAPrivateDecryptH: Private key length %u\n", dbytes); + TPM_PrintFour(" TPM_RSAPrivateDecryptH: Public key", narr); + printf(" TPM_RSAPrivateDecryptH: Exponent %02x %02x %02x\n", earr[0], earr[1], earr[2]); + TPM_PrintFour(" TPM_RSAPrivateDecryptH: Private key", darr); + /* decrypt with private key */ + rc = TPM_RSAPrivateDecrypt(decrypt_data, /* decrypted data */ + decrypt_data_length, /* length of data put into decrypt_data */ + decrypt_data_size, /* size of decrypt_data buffer */ + tpm_key->algorithmParms.encScheme, /* encryption scheme */ + encrypt_data, /* encrypted data */ + encrypt_data_size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + if (rc == 0) { + TPM_PrintFourLimit(" TPM_RSAPrivateDecryptH: Decrypt data", decrypt_data, *decrypt_data_length); + } + return rc; +} + +/* TPM_RSAPublicEncryptSbuffer_Key() encrypts 'sbuffer' using the public key in 'tpm_key' and + puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncryptSbuffer_Key(TPM_SIZED_BUFFER *enc_data, + TPM_STORE_BUFFER *sbuffer, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + const unsigned char *decrypt_data; /* serialization buffer */ + uint32_t decrypt_data_size; /* serialization size */ + + printf(" TPM_RSAPublicEncryptSbuffer_Key:\n"); + /* get the serialization results */ + TPM_Sbuffer_Get(sbuffer, &decrypt_data, &decrypt_data_size); + /* encrypt the serialization buffer with the public key, and place + the result in the enc_data buffer */ + rc = TPM_RSAPublicEncrypt_Key(enc_data, + decrypt_data, + decrypt_data_size, + tpm_key); + return rc; +} + +/* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key in 'tpm_key' and + puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncrypt_Key(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + printf(" TPM_RSAPublicEncrypt_Key: Data size %lu bytes\n", (unsigned long)decrypt_data_size); + if (rc == 0) { + if (tpm_key == NULL) { + printf("TPM_RSAPublicEncrypt_Key: Error, NULL key\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + /* extract the public key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + if (rc == 0) { + rc = TPM_RSAPublicEncrypt_Common(enc_data, + decrypt_data, + decrypt_data_size, + tpm_key->algorithmParms.encScheme, /* encryption scheme */ + narr, + nbytes, + earr, + ebytes); + } + return rc; +} + +/* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key in 'tpm_pubkey' and + puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncrypt_Pubkey(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + printf(" TPM_RSAPublicEncrypt_Pubkey: Data size %lu bytes\n", (unsigned long)decrypt_data_size); + if (rc == 0) { + if (tpm_pubkey == NULL) { + printf("TPM_RSAPublicEncrypt_Pubkey: Error, NULL key\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + /* extract the public key from TPM_PUBKEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetPublicKey(&nbytes, &narr, tpm_pubkey); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetExponent(&ebytes, &earr, tpm_pubkey); + } + if (rc == 0) { + rc = TPM_RSAPublicEncrypt_Common(enc_data, + decrypt_data, + decrypt_data_size, + tpm_pubkey->algorithmParms.encScheme, + narr, + nbytes, + earr, + ebytes); + } + return rc; +} + +/* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key modulus and + exponent, and puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncrypt_Common(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_ENC_SCHEME encScheme, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) + +{ + TPM_RESULT rc = 0; + unsigned char *encrypt_data = NULL; + + printf(" TPM_RSAPublicEncrypt_Common: Data size %lu bytes\n", (unsigned long)decrypt_data_size); + TPM_PrintFourLimit(" TPM_RSAPublicEncrypt_Common: Decrypt data", decrypt_data, decrypt_data_size); + /* check the key size vs the data size */ + if (rc == 0) { + if (decrypt_data_size > nbytes) { + printf("TPM_RSAPublicEncrypt_Common: Error, data size too long for key size %u bytes\n", + nbytes); + rc = TPM_BAD_DATASIZE; + } + } + /* allocate an array for the encrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&encrypt_data, nbytes); + } + /* pad and encrypt the data */ + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncrypt_Common: Public key", narr); + printf(" TPM_RSAPublicEncrypt_Common: Exponent %02x %02x %02x\n", + earr[0], earr[1], earr[2]); + rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ + nbytes, /* encrypted data size */ + encScheme, /* encryption scheme */ + decrypt_data, /* decrypted data */ + decrypt_data_size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + /* copy the result to the sized buffer */ + if (rc == 0) { + printf(" TPM_RSAPublicEncrypt_Common: Encrypt data size %u\n", nbytes); + TPM_PrintFour(" TPM_RSAPublicEncrypt_Common: Encrypt data", encrypt_data); + rc = TPM_SizedBuffer_Set(enc_data, nbytes, encrypt_data); + } + free(encrypt_data); /* @1 */ + return rc; +} + +/* + Signing Functions + + These commands show the TPM command and the allowed signature schemes: + + SHA DER INFO + TPM_GetAuditDigestSigned y n y + TPM_CertifyKey y n y + TPM_CertifyKey2 y n y + TPM_CertifySelfTest y n y + TPM_Quote y n y + TPM_Quote2 y n y + TPM_Sign y y y + TPM_MakeIdentity y n y + TPM_GetCapabilitySigned y n y +*/ + +/* TPM_RSASignToSizedBuffer() signs 'message' using the private key in 'tpm_key' and places the + result in 'signature' + + 'signature' should be initialized and deleted by the caller +*/ + +TPM_RESULT TPM_RSASignToSizedBuffer(TPM_SIZED_BUFFER *signature, + const unsigned char *message, /* input */ + size_t message_size, /* input */ + TPM_KEY *tpm_key) /* input, signing key */ +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *rsa_key_parms; + unsigned int signature_length; + + printf(" TPM_RSASignToSizedBuffer: Message size %lu bytes\n", (unsigned long)message_size); + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&rsa_key_parms, + &(tpm_key->algorithmParms)); + } + /* allocating space for the signature */ + if (rc == 0) { + rc = TPM_SizedBuffer_Allocate(signature, (rsa_key_parms->keyLength)/CHAR_BIT); + } + /* sign */ + if (rc == 0) { + rc = TPM_RSASignH(signature->buffer, /* output signature */ + &signature_length, /* output, size of signature */ + signature->size, /* input, size of signature buffer */ + message, /* message */ + message_size, /* message size */ + tpm_key); /* input, signing key */ + } + /* sanity check on signature */ + if (rc == 0) { + if (signature_length != signature->size) { + printf("TPM_RSASignToSizedBuffer: Error (fatal) signature_length %u sigSize %u\n", + signature_length, signature->size); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + return rc; +} + + +/* TPM_RSASignH() signs 'message' using the private key in 'tpm_key'. 'signature_length' bytes are + moved to 'signature'. + + 'signature_length' is at most 'signature_size'. +*/ + +TPM_RESULT TPM_RSASignH(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + unsigned int signature_size, /* input, size of signature buffer */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + TPM_KEY *tpm_key) /* input, signing key */ +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + unsigned char *darr; /* private exponent */ + uint32_t dbytes; + + printf(" TPM_RSASignH: Message size %lu bytes\n", (unsigned long)message_size); + TPM_PrintFourLimit(" TPM_RSASignH: Message", message, message_size); + /* extract the public key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + /* extract the private key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPrivateKey(&dbytes, &darr, tpm_key); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + if (rc == 0) { + /* debug printing */ + TPM_PrintFour(" TPM_RSASignH: Public key", narr); + printf(" TPM_RSASignH: Exponent %02x %02x %02x\n", earr[0], earr[1], earr[2]); + TPM_PrintFour(" TPM_RSASignH: Private key", darr); + /* sign with private key */ + rc = TPM_RSASign(signature, /* output */ + signature_length, /* output, size of signature */ + signature_size, /* input, size of signature buffer */ + tpm_key->algorithmParms.sigScheme, /* input, type of signature */ + message, /* input */ + message_size, /* input */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSASignH: Signature", signature); + } + return rc; +} + +/* TPM_RSAVerifyH() verifies 'message' using the TPM format public key in 'tpm_pubkey' +*/ + +TPM_RESULT TPM_RSAVerifyH(TPM_SIZED_BUFFER *signature, /* input */ + const unsigned char *message, /* input */ + uint32_t message_size, /* input */ + TPM_PUBKEY *tpm_pubkey) /* input, verify key */ +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + printf(" TPM_RSAVerifyH: Message size %u bytes\n", message_size); + /* extract the public key from TPM_PUBKEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetPublicKey(&nbytes, &narr, tpm_pubkey); + } + /* extract the exponent from TPM_PUBKEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetExponent(&ebytes, &earr, tpm_pubkey); + } + if (rc == 0) { + /* debug printing */ + TPM_PrintFour(" TPM_RSAVerifyH: Public key", narr); + TPM_PrintAll(" TPM_RSAVerifyH: Public exponent", earr, ebytes); + /* verify with public key */ + rc = TPM_RSAVerify(signature->buffer, /* input signature buffer */ + signature->size, /* input, size of signature buffer */ + tpm_pubkey->algorithmParms.sigScheme, /* input, type of signature */ + message, /* message */ + message_size, /* message size */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + return rc; +} + +/* TPM_RSAVerify() verifies the 'signature' of size 'signature_size' on the 'message' of size + 'message_size' using the public key n,e and the signature scheme 'sigScheme' as specified in PKCS + #1 v2.0. +*/ + +TPM_RESULT TPM_RSAVerify(unsigned char *signature, /* input */ + unsigned int signature_size, /* input, size of signature buffer */ + TPM_SIG_SCHEME sigScheme, /* input, type of signature */ + const unsigned char *message, /* input */ + uint32_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAVerify:\n"); + /* determine the signature scheme for the key */ + if (rc == 0) { + switch(sigScheme) { + case TPM_SS_NONE: + printf("TPM_RSAVerify: Error, sigScheme TPM_SS_NONE\n"); + rc = TPM_INVALID_KEYUSAGE; + break; + case TPM_SS_RSASSAPKCS1v15_SHA1: + case TPM_SS_RSASSAPKCS1v15_INFO: + rc = TPM_RSAVerifySHA1(signature, + signature_size, + message, + message_size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + break; + case TPM_SS_RSASSAPKCS1v15_DER: + printf("TPM_RSAVerify: Error, sigScheme %04hx unsupported\n", sigScheme); + rc = TPM_INVALID_KEYUSAGE; + break; + default: + printf("TPM_RSAVerify: Error, sigScheme %04hx unknown\n", sigScheme); + rc = TPM_INVALID_KEYUSAGE; + break; + } + } + return rc; +} + +/* + OAEP Padding +*/ + +/* TPM_RSA_padding_add_PKCS1_OAEP() is a variation of the the openSSL function + + int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen, + unsigned char *f, int fl, unsigned char *p, int pl); + + It is used for TPM migration. The "encoding parameter" pl is replaced by pHash and the generated + random seed is replaced by a seed parameter. + + This function was independently written from the PKCS1 specification "9.1.1.1 Encoding + Operation", intended to be unencumbered by any license. + + + | seed | pHash | PS | 01 | Message | + + SHA1 SHA1 flen + + | <- emLen -> | + | db + | maskDb + | dbMask | + | seedMask + | maskSeed +*/ + +TPM_RESULT TPM_RSA_padding_add_PKCS1_OAEP(unsigned char *em, uint32_t emLen, + const unsigned char *from, uint32_t fLen, + const unsigned char *pHash, /* input 20 bytes */ + const unsigned char *seed) /* input 20 bytes */ +{ + TPM_RESULT rc = 0; + unsigned char *dbMask; + unsigned char *db; + unsigned char *maskedDb; + unsigned char *seedMask; + unsigned char *maskedSeed; + + printf(" TPM_RSA_padding_add_PKCS1_OAEP: fLen %d emLen %d\n", fLen, emLen); + TPM_PrintFourLimit(" TPM_RSA_padding_add_PKCS1_OAEP: from", from, fLen); + TPM_PrintFour(" TPM_RSA_padding_add_PKCS1_OAEP: pHash", pHash); + TPM_PrintFour(" TPM_RSA_padding_add_PKCS1_OAEP: seed", seed); + + dbMask = NULL; /* freed @1 */ + + /* 1. If the length of P is greater than the input limitation for */ + /* the hash function (2^61-1 octets for SHA-1) then output "parameter */ + /* string too long" and stop. */ + /* NOTE Not done, pHash is input directly */ + /* 2. If ||M|| > emLen-2hLen-1 then output "message too long" and stop. */ + if (rc == 0) { + if (emLen < ((2 * TPM_DIGEST_SIZE) + 1 + fLen)) { + printf("TPM_RSA_padding_add_PKCS1_OAEP: Error, " + "message length %u too large for encoded length %u\n", fLen, emLen); + rc = TPM_ENCRYPT_ERROR; + } + } + /* 3. Generate an octet string PS consisting of emLen-||M||-2hLen-1 zero octets. The length of + PS may be 0. */ + /* NOTE Created directly in DB (step 5) */ + + /* 4. Let pHash = Hash(P), an octet string of length hLen. */ + /* NOTE pHash is input directly */ + + /* 5. Concatenate pHash, PS, the message M, and other padding to form a data block DB as: DB = + pHash || PS || 01 || M */ + if (rc == 0) { + /* NOTE Since db is eventually maskedDb, part of em, create directly in em */ + db = em + TPM_DIGEST_SIZE; + memcpy(db, pHash, TPM_DIGEST_SIZE); /* pHash */ + memset(db + TPM_DIGEST_SIZE, 0, /* PS */ + emLen - fLen - (2 * TPM_DIGEST_SIZE) - 1); + /* PSlen = emlen - flen - (2 * TPM_DIGEST_SIZE) - 1 + 0x01 index = TPM_DIGEST_SIZE + PSlen + = TPM_DIGEST_SIZE + emlen - flen - (2 * TPM_DIGEST_SIZE) - 1 + = emlen - fLen - TPM_DIGEST_SIZE - 1 */ + db[emLen - fLen - TPM_DIGEST_SIZE - 1] = 0x01; + memcpy(db + emLen - fLen - TPM_DIGEST_SIZE, from, fLen); /* M */ + + /* 6. Generate a random octet string seed of length hLen. */ + /* NOTE seed is input directly */ + + /* 7. Let dbMask = MGF(seed, emLen-hLen). */ + rc = TPM_Malloc(&dbMask, emLen - TPM_DIGEST_SIZE); + } + if (rc == 0) { + rc = TPM_MGF1(dbMask, emLen - TPM_DIGEST_SIZE, seed, TPM_DIGEST_SIZE); + } + if (rc == 0) { + /* 8. Let maskedDB = DB \xor dbMask. */ + /* NOTE Since maskedDB is eventually em, XOR directly to em */ + maskedDb = em + TPM_DIGEST_SIZE; + TPM_XOR(maskedDb, db, dbMask, emLen - TPM_DIGEST_SIZE); + + /* 9. Let seedMask = MGF(maskedDB, hLen). */ + /* NOTE Since seedMask is eventually em, create directly to em */ + seedMask = em; + rc = TPM_MGF1(seedMask, TPM_DIGEST_SIZE, maskedDb, emLen - TPM_DIGEST_SIZE); + } + if (rc == 0) { + /* 10. Let maskedSeed = seed \xor seedMask. */ + /* NOTE Since maskedSeed is eventually em, create directly to em */ + maskedSeed = em; + TPM_XOR(maskedSeed, seed, seedMask, TPM_DIGEST_SIZE); + + /* 11. Let EM = maskedSeed || maskedDB. */ + /* NOTE Created directly in em */ + + /* 12. Output EM. */ + TPM_PrintFourLimit(" TPM_RSA_padding_add_PKCS1_OAEP: em", em, emLen); + } + free(dbMask); /* @1 */ + return rc; +} + +/* TPM_RSA_padding_check_PKCS1_OAEP() is a variation of the openSSL function + + int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen, + unsigned char *f, int fl, int rsa_len, unsigned char *p, int pl); + + It is used for TPM key migration. In addition to the message 'to' and message length 'tlen', the + seed and 'pHash are returned. + + This function was independently written from the PKCS1 specification "9.1.1.2 Decoding + Operation", intended to be unencumbered by the any license. + + | seed | pHash | PS | 01 | Message | + SHA1 SHA1 + | <- emLen -> | + + | maskedSeed + | seedMask + | maskedDB + | db + | <- dbMask -> | + +*/ + +TPM_RESULT TPM_RSA_padding_check_PKCS1_OAEP(unsigned char *to, uint32_t *tLen, uint32_t tSize, + const unsigned char *em, uint32_t emLen, + unsigned char *pHash, /* output 20 bytes */ + unsigned char *seed) /* output 20 bytes */ +{ + TPM_RESULT rc = 0; + const unsigned char *maskedSeed; + const unsigned char *maskedDB; + uint32_t dbLen; + unsigned char *dbMask; + unsigned char *seedMask; + unsigned char *db; + size_t i; + + printf(" TPM_RSA_padding_check_PKCS1_OAEP: emLen %d tSize %d\n", emLen, tSize); + TPM_PrintFourLimit(" TPM_RSA_padding_check_PKCS1_OAEP: em", em, emLen); + + dbMask = NULL; /* freed @1 */ + + /* 1. If the length of P is greater than the input limitation for the hash function (2^61-1 + octets for SHA-1) then output "parameter string too long" and stop. */ + /* NOTE There is no P input. pHash is calculated for the output, but no comparison is + performed. */ + + /* 2. If ||EM|| < 2hLen+1, then output "decoding error" and stop. */ + if (rc == 0) { + if (emLen < (2 * TPM_DIGEST_SIZE) + 1) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, encoded length %u too small\n", emLen); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* 3. Let maskedSeed be the first hLen octets of EM and let maskedDB be the remaining ||EM|| + - hLen octets. */ + maskedSeed = em; + maskedDB = em + TPM_DIGEST_SIZE; + dbLen = emLen - TPM_DIGEST_SIZE; + /* 4. Let seedMask = MGF(maskedDB, hLen). */ + /* NOTE Created directly in seed */ + seedMask = seed; + rc = TPM_MGF1(seedMask, TPM_DIGEST_SIZE, maskedDB, dbLen); + } + if (rc == 0) { + /* 5. Let seed = maskedSeed \xor seedMask. */ + TPM_XOR(seed, maskedSeed, seedMask, TPM_DIGEST_SIZE); + /* 6. Let dbMask = MGF(seed, ||EM|| - hLen). */ + rc = TPM_Malloc(&dbMask, dbLen); + } + if (rc == 0) { + rc = TPM_MGF1(dbMask, dbLen, seed, TPM_DIGEST_SIZE); + } + if (rc == 0) { + /* 7. Let DB = maskedDB \xor dbMask. */ + /* NOTE XOR back to dbMask, since dbMask no longer needed */ + db = dbMask; + TPM_XOR(db, maskedDB, dbMask, dbLen); + /* 8. Let pHash = Hash(P), an octet string of length hLen. */ + /* NOTE pHash is input directly */ + /* 9. Separate DB into an octet string pHash' consisting of the first hLen octets of DB, + ... */ + memcpy(pHash, db, TPM_DIGEST_SIZE); + /* ... a (possibly empty) octet string PS consisting of consecutive zero octets following + pHash', and a message M as: DB = pHash' || PS || 01 || M */ + for (i = TPM_DIGEST_SIZE; i < dbLen; i++) { + if (db[i] != 0x00) { + break; /* skip the PS segment */ + } + } + /* If there is no 01 octet to separate PS from M, output "decoding error" and stop. */ + if (i == dbLen) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, missing 0x01\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + if (db[i] != 0x01) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, missing 0x01\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* 10. If pHash' does not equal pHash, output "decoding error" and stop. */ + /* NOTE No pHash input to compare */ + /* 11. Output M. */ + if (rc == 0) { + i++; /* skip the 0x01 to the beginning of the message M */ + *tLen = dbLen - i; + if (*tLen > tSize) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, tSize %u too small for message %u\n", + tSize, *tLen); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + memcpy(to, db + i, *tLen); + printf(" TPM_RSA_padding_check_PKCS1_OAEP: tLen %d \n", *tLen); + TPM_PrintFourLimit(" TPM_RSA_padding_check_PKCS1_OAEP: to", to, *tLen); + TPM_PrintFour(" TPM_RSA_padding_check_PKCS1_OAEP: pHash", pHash); + TPM_PrintFour(" TPM_RSA_padding_check_PKCS1_OAEP: seed", seed); + } + free(dbMask); /* @1 */ + return rc; +} + +/* TPM_RSA_exponent_verify() validates the public exponent against a list of legal values. Some + values (e.g. even numbers) will have the key generator. +*/ + +TPM_RESULT TPM_RSA_exponent_verify(unsigned long exponent) +{ + TPM_RESULT rc = 0; + size_t i; + int found; + + static const unsigned long legalExponent[] = { 3,5,7,17,257,65537 }; + + for (i = 0, found = FALSE ; + !found && (i < (sizeof(legalExponent) / sizeof (unsigned long))) ; + i++) { + + if (exponent == legalExponent[i]) { + found = TRUE; + } + } + if (!found) { + printf("TPM_RSA_exponent_verify: Error, public exponent %lu is illegal\n", exponent ); + rc = TPM_BAD_KEY_PROPERTY; + } + return rc; +} + +/* SHA1 and HMAC test driver + + Returns TPM_FAILEDSELFTEST on error +*/ + +TPM_RESULT TPM_CryptoTest(void) +{ + TPM_RESULT rc = 0; + int not_equal; + TPM_BOOL valid; + + /* SHA1 */ + unsigned char buffer1[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + unsigned char expect1[] = {0x84,0x98,0x3E,0x44,0x1C, + 0x3B,0xD2,0x6E,0xBA,0xAE, + 0x4A,0xA1,0xF9,0x51,0x29, + 0xE5,0xE5,0x46,0x70,0xF1}; + TPM_DIGEST actual; + uint32_t actual_size; + + /* HMAC */ + unsigned char key2[] = {0xaa,0xaa,0xaa,0xaa,0xaa, 0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa, 0xaa,0xaa,0xaa,0xaa,0xaa}; + unsigned char expect2[] = {0x12,0x5d,0x73,0x42,0xb9,0xac,0x11,0xcd,0x91,0xa3, + 0x9a,0xf4,0x8a,0xa1,0x7b,0x4f,0x63,0xf1,0x75,0xd3}; + /* data 0xdd repeated 50 times */ + unsigned char data2[50]; + + /* oaep tests */ + const unsigned char oaep_pad_str[] = { 'T', 'C', 'P', 'A' }; + unsigned char pHash_in[TPM_DIGEST_SIZE]; + unsigned char pHash_out[TPM_DIGEST_SIZE]; + unsigned char seed_in[TPM_DIGEST_SIZE] = {0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, + 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff, + 0xf0,0xf1,0xf2,0xf3}; + unsigned char seed_out[TPM_DIGEST_SIZE]; + unsigned char oaep_in[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; + unsigned char oaep_pad[256]; + unsigned char oaep_out[8]; + uint32_t oeap_length; + + /* symmetric key with pad */ + TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_data = NULL; /* opaque structure, freed @7 */ + unsigned char clrStream[64]; /* expected */ + unsigned char *encStream; /* encrypted */ + uint32_t encSize; + unsigned char *decStream; /* actual */ + uint32_t decSize; + + /* symmetric key ctr and ofb mode */ + TPM_SECRET symKey; + TPM_NONCE pad; /* CTR or IV */ + TPM_ENCAUTH symClear; + TPM_ENCAUTH symEnc; + TPM_ENCAUTH symDec; + + /* RSA encrypt and decrypt, sign and verify */ + unsigned char *n; /* public key - modulus */ + unsigned char *p; /* private key prime */ + unsigned char *q; /* private key prime */ + unsigned char *d; /* private key (private exponent) */ + unsigned char encrypt_data[2048/8]; /* encrypted data */ + unsigned char signature[2048/8]; /* signature; libtpms added */ + + printf(" TPM_CryptoTest:\n"); + encStream = NULL; /* freed @1 */ + decStream = NULL; /* freed @2 */ + n = NULL; /* freed @3 */ + p = NULL; /* freed @4 */ + q = NULL; /* freed @5 */ + d = NULL; /* freed @6 */ + + if (rc == 0) { + printf(" TPM_CryptoTest: Test 1 - SHA1 one part\n"); + rc = TPM_SHA1(actual, + sizeof(buffer1) - 1, buffer1, + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 1\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 2 - SHA1 two parts\n"); + rc = TPM_SHA1(actual, + 16, buffer1, /* first 16 */ + sizeof(buffer1) - 17, buffer1 + 16, /* rest */ + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 2\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 3 - HMAC generate - one part\n"); + memset(data2, 0xdd, 50); + rc = TPM_HMAC_Generate(actual, + key2, + 50, data2, + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect2, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 3\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 4 - HMAC generate - two parts\n"); + memset(data2, 0xdd, 50); + rc = TPM_HMAC_Generate(actual, + key2, + 20, data2, + 30, data2 + 20, + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect2, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 3\n"); + TPM_PrintFour("\texpect", expect2); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 4 - HMAC check - two parts\n"); + memset(data2, 0xdd, 50); + rc = TPM_HMAC_Check(&valid, + expect2, + key2, + 20, data2, + 30, data2 + 20, + 0, NULL); + } + if (rc == 0) { + if (!valid) { + printf("TPM_CryptoTest: Error in test 4\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 5 - OAEP add and check\n"); + rc = TPM_SHA1(pHash_in, + sizeof(oaep_pad_str), oaep_pad_str, + 0, NULL); + } + if (rc == 0) { + rc = TPM_RSA_padding_add_PKCS1_OAEP(oaep_pad, sizeof(oaep_pad), + oaep_in, sizeof(oaep_in), + pHash_in, seed_in); + } + if (rc == 0) { + rc = TPM_RSA_padding_check_PKCS1_OAEP(oaep_out, &oeap_length, sizeof(oaep_out), + oaep_pad, sizeof(oaep_pad), + pHash_out, + seed_out); + } + if (rc == 0) { + if (oeap_length != sizeof(oaep_out)) { + printf("TPM_CryptoTest: Error in test 5, expect length %lu, actual length %u\n", + (unsigned long)sizeof(oaep_out), oeap_length); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(oaep_in, oaep_out, sizeof(oaep_out)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 5 oaep\n"); + TPM_PrintFour("\tin ", oaep_in); + TPM_PrintFour("\tout", oaep_out); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(pHash_in, pHash_out, sizeof(pHash_in)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 5 pHash\n"); + TPM_PrintFour("\tpHash_in ", pHash_in); + TPM_PrintFour("\tpHash_out", pHash_out); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(seed_in, seed_out, sizeof(seed_in)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 5 seed\n"); + TPM_PrintFour("\tseed_in ", seed_in); + TPM_PrintFour("\tseed_out", seed_out); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 6 - Symmetric key with PKCS pad test\n"); + /* allocate memory for the key token */ + rc = TPM_SymmetricKeyData_New(&tpm_symmetric_key_data); /* freed @7 */ + } + /* generate a key */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_GenerateKey(tpm_symmetric_key_data); + } + /* generate clear text */ + if (rc == 0) { + rc = TPM_Random(clrStream, sizeof(clrStream)); + } + /* symmetric encrypt */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Encrypt(&encStream, /* output, freed @1 */ + &encSize, /* output */ + clrStream, /* input */ + sizeof(clrStream), /* input */ + tpm_symmetric_key_data); /* key */ + } + /* symmetric decrypt */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Decrypt(&decStream, /* output, freed by caller */ + &decSize, /* output */ + encStream, /* input */ + encSize, /* input */ + tpm_symmetric_key_data); /* key */ + } + /* symmetric compare */ + if (rc == 0) { + if (sizeof(clrStream) != decSize) { + printf("TPM_CryptoTest: Error in test 6, in %lu, out %u\n", + (unsigned long)sizeof(clrStream), decSize); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(clrStream, decStream, sizeof(clrStream)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 6\n"); + TPM_PrintFour("\tclear stream in", clrStream); + TPM_PrintFour("\tdecrypted stream", decStream); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 7 - Symmetric key with CTR mode\n"); + /* generate a key */ + rc = TPM_Random(symKey, TPM_SECRET_SIZE); + } + /* generate CTR */ + if (rc == 0) { + rc = TPM_Random(pad, TPM_NONCE_SIZE); + } + /* generate clear text */ + if (rc == 0) { + rc = TPM_Random(symClear, TPM_AUTHDATA_SIZE); + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_CtrCrypt(symEnc, /* output */ + symClear, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_CtrCrypt(symDec, /* output */ + symEnc, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + /* symmetric compare */ + if (rc == 0) { + rc = TPM_Secret_Compare(symDec, symClear); + if (rc != 0) { + printf("TPM_CryptoTest: Error in test 8\n"); + TPM_PrintFour("\tclear stream in", symClear); + TPM_PrintFour("\tdecrypted stream", symDec); + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 8 - Symmetric key with OFB mode\n"); + /* generate a key */ + rc = TPM_Random(symKey, TPM_SECRET_SIZE); + } + /* generate IV */ + if (rc == 0) { + rc = TPM_Random(pad, TPM_NONCE_SIZE); + } + /* generate clear text */ + if (rc == 0) { + rc = TPM_Random(symClear, TPM_AUTHDATA_SIZE); + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_OfbCrypt(symEnc, /* output */ + symClear, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_OfbCrypt(symDec, /* output */ + symEnc, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + /* symmetric compare */ + if (rc == 0) { + rc = TPM_Secret_Compare(symDec, symClear); + if (rc != 0) { + printf("TPM_CryptoTest: Error in test 8\n"); + TPM_PrintFour("\tclear stream in", symClear); + TPM_PrintFour("\tdecrypted stream", symDec); + } + } + /* RSA OAEP encrypt and decrypt */ + if (rc == 0) { + printf(" TPM_CryptoTest: Test 9 - RSA encrypt with OAEP padding\n"); + /* generate a key */ + rc = TPM_RSAGenerateKeyPair(&n, /* public key - modulus */ + &p, /* private key prime */ + &q, /* private key prime */ + &d, /* private key (private exponent) */ + 2048, /* key size in bits */ + tpm_default_rsa_exponent, /* public exponent as an array */ + 3); + } + /* encrypt */ + if (rc == 0) { + rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ + sizeof(encrypt_data), /* size of encrypted data buffer */ + TPM_ES_RSAESOAEP_SHA1_MGF1, /* TPM_ENC_SCHEME */ + expect1, /* decrypted data */ + sizeof(expect1), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3); + } + if (rc == 0) { + rc = TPM_RSAPrivateDecrypt(actual, /* decrypted data */ + &actual_size, /* length of data put into + decrypt_data */ + TPM_DIGEST_SIZE, /* size of decrypt_data buffer */ + TPM_ES_RSAESOAEP_SHA1_MGF1, /* TPM_ENC_SCHEME */ + encrypt_data, /* encrypted data */ + sizeof(encrypt_data), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3, + d, /* private exponent */ + 2048/8); + } + if (rc == 0) { + if (actual_size != TPM_DIGEST_SIZE) { + printf("TPM_CryptoTest: Error in test 9, expect length %u, actual length %u\n", + TPM_DIGEST_SIZE, actual_size); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 9\n"); + TPM_PrintFour("\tin ", expect1); + TPM_PrintFour("\tout", actual); + rc = TPM_FAILEDSELFTEST; + } + } + /* RSA PKCS1 pad, encrypt and decrypt */ + if (rc == 0) { + printf(" TPM_CryptoTest: Test 10 - RSA encrypt with PKCS padding\n"); + /* encrypt */ + rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ + sizeof(encrypt_data), /* size of encrypted data buffer */ + TPM_ES_RSAESPKCSv15, /* TPM_ENC_SCHEME */ + expect1, /* decrypted data */ + sizeof(expect1), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3); + } + /* decrypt */ + if (rc == 0) { + rc = TPM_RSAPrivateDecrypt(actual, /* decrypted data */ + &actual_size, /* length of data put into + decrypt_data */ + TPM_DIGEST_SIZE, /* size of decrypt_data buffer */ + TPM_ES_RSAESPKCSv15, /* TPM_ENC_SCHEME */ + encrypt_data, /* encrypted data */ + sizeof(encrypt_data), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3, + d, /* private exponent */ + 2048/8); + } + /* check length after padding removed */ + if (rc == 0) { + if (actual_size != TPM_DIGEST_SIZE) { + printf("TPM_CryptoTest: Error in test 10, expect length %u, actual length %u\n", + TPM_DIGEST_SIZE, actual_size); + rc = TPM_FAILEDSELFTEST; + } + } + /* check data */ + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 10\n"); + TPM_PrintFour("\tin ", expect1); + TPM_PrintFour("\tout", actual); + rc = TPM_FAILEDSELFTEST; + } + } + +// libtpms added begin + + if (rc == 0) { + printf(" TPM_CryptoTest: Test 11a - RSA sign with PKCS1v15 padding\n"); + rc = TPM_RSASign(signature, + &actual_size, + sizeof(signature), + TPM_SS_RSASSAPKCS1v15_SHA1, + expect1, + sizeof(expect1), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3, + d, /* private exponent */ + 2048/8); + } + if (rc == 0) { + rc = TPM_RSAVerify(signature, /* input signature buffer */ + sizeof(signature), /* input, size of signature buffer */ + TPM_SS_RSASSAPKCS1v15_SHA1, /* input, type of signature */ + expect1, /* message */ + sizeof(expect1), /* message size */ + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent,/* public exponent */ + 3); + } + +#if 0 + /* Verification with TPM_SS_RSASSAPKCS1v15_DER is not supported */ + if (rc == 0) { + printf(" TPM_CryptoTest: Test 11b - RSA sign with PKCS1v15_DER padding\n"); + rc = TPM_RSASign(signature, + &actual_size, + sizeof(signature), + TPM_SS_RSASSAPKCS1v15_DER, + expect1, + sizeof(expect1), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3, + d, /* private exponent */ + 2048/8); + } + if (rc == 0) { + rc = TPM_RSAVerify(signature, /* input signature buffer */ + sizeof(signature), /* input, size of signature buffer */ + TPM_SS_RSASSAPKCS1v15_DER, /* input, type of signature */ + expect1, /* message */ + sizeof(expect1), /* message size */ + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent,/* public exponent */ + 3); + } +#endif // libtpms added end + + /* run library specific self tests as required */ + if (rc == 0) { + rc = TPM_Crypto_TestSpecific(); + } + if (rc != 0) { + rc = TPM_FAILEDSELFTEST; + } + free(encStream); /* @1 */ + free(decStream); /* @2 */ + free(n); /* @3 */ + free(p); /* @4 */ + free(q); /* @5 */ + free(d); /* @6 */ + TPM_SymmetricKeyData_Free(&tpm_symmetric_key_data); /* @7 */ + return rc; +} + +/* 13.5 TPM_Sign rev 111 + + The Sign command signs data and returns the resulting digital signature. + + The TPM does not allow TPM_Sign with a TPM_KEY_IDENTITY (AIK) because TPM_Sign can sign arbitrary + data and could be used to fake a quote. (This could have been relaxed to allow TPM_Sign with an + AIK if the signature scheme is _INFO For an _INFO key, the metadata prevents TPM_Sign from faking + a quote.) + + The TPM MUST support all values of areaToSignSize that are legal for the defined signature scheme + and key size. The maximum value of areaToSignSize is determined by the defined signature scheme + and key size. + + In the case of PKCS1v15_SHA1 the areaToSignSize MUST be TPM_DIGEST (the hash size of a sha1 + operation - see 8.5.1 TPM_SS_RSASSAPKCS1v15_SHA1). In the case of PKCS1v15_DER the maximum size + of areaToSign is k - 11 octets, where k is limited by the key size (see 8.5.2 + TPM_SS_RSASSAPKCS1v15_DER). +*/ + +TPM_RESULT TPM_Process_Sign(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 + digital signatures. */ + TPM_SIZED_BUFFER areaToSign; /* The value to sign */ + 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 privAuth; /* The authorization digest that authorizes the use of + keyHandle. HMAC key: key.usageAuth */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus ; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_RSA_KEY_PARMS *rsa_key_parms; /* for key */ + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *keyUsageAuth; + TPM_SIGN_INFO tpm_sign_info; + const unsigned char *S1_data; /* data to be signed */ + uint32_t S1_size; + TPM_DIGEST infoDigest; /* TPM_SIGN_INFO structure digest */ + TPM_STORE_BUFFER sbuffer; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_Sign: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&areaToSign); /* freed @1 */ + TPM_SignInfo_Init(&tpm_sign_info); /* freed @2 */ + TPM_Sbuffer_Init(&sbuffer); /* freed @3 */ + TPM_SizedBuffer_Init(&sig); /* freed @4 */ + /* + 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_Sign: keyHandle %08x\n", keyHandle); + /* get areaToSignSize and areaToSign parameters */ + returnCode = TPM_SizedBuffer_Load(&areaToSign, &command, ¶mSize); /* freed @1 */ + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sign: Signing %u bytes\n", areaToSign.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_Sign: 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, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* check TPM_AUTH_DATA_USAGE authDataUsage */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (key->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_Sign: 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 */ + } + /* 1. The TPM validates the AuthData 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 */ + } + /* 2. If the areaToSignSize is 0 the TPM returns TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if (areaToSign.size == 0) { + printf("TPM_Process_Sign: Error, areaToSignSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 3. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING or TPM_KEY_LEGACY, if not return + the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((key->keyUsage != TPM_KEY_SIGNING) && ((key->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_Sign: Error, keyUsage %04hx is invalid\n", key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. The TPM verifies that the signature scheme and key size can properly sign the areaToSign + parameter. NOTE Done in 5. - 7.*/ + /* get key -> TPM_RSA_KEY_PARMS */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&rsa_key_parms, + &(key->algorithmParms)); + } + if (returnCode == TPM_SUCCESS) { + /* 5. If signature scheme is TPM_SS_RSASSAPKCS1v15_SHA1 then */ + if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1\n"); + /* a. Validate that areaToSignSize is 20 return TPM_BAD_PARAMETER on error */ + if (returnCode == TPM_SUCCESS) { + if (areaToSign.size != TPM_DIGEST_SIZE) { + printf("TPM_Process_Sign: Error, areaToSignSize %d should be %u\n", + areaToSign.size, TPM_DIGEST_SIZE); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. Set S1 to areaToSign */ + if (returnCode == TPM_SUCCESS) { + S1_size = areaToSign.size; + S1_data = areaToSign.buffer; + } + } + /* 6. Else if signature scheme is TPM_SS_RSASSAPKCS1v15_DER then */ + else if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_DER) { + printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_DER\n"); + /* a. Validate that areaToSignSize is at least 11 bytes less than the key size, return + TPM_BAD_PARAMETER on error */ + if (returnCode == TPM_SUCCESS) { + if (areaToSign.size > (((rsa_key_parms->keyLength)/CHAR_BIT) - 11)) { + printf("TPM_Process_Sign: Error, areaToSignSize %d should be 11-%u\n", + areaToSign.size, ((rsa_key_parms->keyLength)/CHAR_BIT)); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. Set S1 to areaToSign */ + if (returnCode == TPM_SUCCESS) { + S1_size = areaToSign.size; + S1_data = areaToSign.buffer; + } + } + /* 7. else if signature scheme is TPM_SS_RSASSAPKCS1v15_INFO then */ + else if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_INFO) { + printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_INFO\n"); + if (returnCode == TPM_SUCCESS) { + /* a. Create S2 a TPM_SIGN_INFO structure */ + /* NOTE: Done by TPM_SignInfo_Init() */ + /* b. Set S2 -> fixed to "SIGN" */ + memcpy(tpm_sign_info.fixed, "SIGN", TPM_SIGN_INFO_FIXED_SIZE); + /* c.i. If nonceOdd is not present due to an unauthorized command return + TPM_BAD_PARAMETER */ + if (tag == TPM_TAG_RQU_COMMAND) { + printf("TPM_Process_Sign: Error, TPM_SS_RSASSAPKCS1v15_INFO and no auth\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + /* c. Set S2 -> replay to nonceOdd */ + TPM_Nonce_Copy(tpm_sign_info.replay, nonceOdd); + /* d. Set S2 -> dataLen to areaToSignSize */ + /* e. Set S2 -> data to areaToSign */ + returnCode = TPM_SizedBuffer_Copy(&(tpm_sign_info.data), &areaToSign); + } + /* f. Set S1 to the SHA-1(S2) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(infoDigest, + &tpm_sign_info, + (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); + S1_size = TPM_DIGEST_SIZE; + S1_data = infoDigest; + } + } + /* 8. Else return TPM_INVALID_KEYUSAGE */ + else { + printf("TPM_Process_Sign: Error, sigScheme %04hx\n", key->algorithmParms.sigScheme); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 9. The TPM computes the signature, sig, using the key referenced by keyHandle using S1 as the + value to sign */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintAll("TPM_Process_Sign: Digest to sign", S1_data, S1_size); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + S1_data, /* message */ + S1_size, /* message size */ + key); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Sign: 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 signature in Sig */ + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* 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_SizedBuffer_Delete(&areaToSign); /* @1 */ + TPM_SignInfo_Delete(&tpm_sign_info); /* @2 */ + TPM_Sbuffer_Delete(&sbuffer); /* @3 */ + TPM_SizedBuffer_Delete(&sig); /* @4 */ + return rcf; +} + +/* 13.1 TPM_SHA1Start rev 96 + + This capability starts the process of calculating a SHA-1 digest. + + The exposure of the SHA-1 processing is a convenience to platforms in a mode that do not have + sufficient memory to perform SHA-1 themselves. As such the use of SHA-1 is restrictive on the + TPM. + + The TPM may not allow any other types of processing during the execution of a SHA-1 + session. There is only one SHA-1 session active on a TPM. The exclusivity of a SHA-1 + context is due to the relatively large volatile buffer it requires in order to hold the + intermediate results between the SHA-1 context commands. This buffer can be in + contradiction to other command needs. + + After the execution of SHA1Start, and prior to SHA1End, the receipt of any command other than + SHA1Update will cause the invalidation of the SHA-1 session. +*/ + +TPM_RESULT TPM_Process_SHA1Start(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 - none */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + uint32_t maxNumBytes = TPM_SHA1_MAXNUMBYTES; /* Maximum number of bytes that can be sent + to TPM_SHA1Update. Must be a multiple of + 64 bytes. */ + + printf("TPM_Process_SHA1Start: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1Start: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This capability prepares the TPM for a subsequent TPM_SHA1Update, TPM_SHA1Complete or + TPM_SHA1CompleteExtend command. The capability SHALL open a thread that calculates a SHA-1 + digest. + */ + if (returnCode == TPM_SUCCESS) { + if (transportInternal == NULL) { + tpm_state->transportHandle = 0; /* SHA-1 thread not within transport */ + } + else { + tpm_state->transportHandle = transportInternal->transHandle; /* SHA-1 thread within + transport */ + } + returnCode = TPM_SHA1InitCmd(&(tpm_state->sha1_context)); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1Start: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append maxNumBytes */ + returnCode = TPM_Sbuffer_Append32(response, maxNumBytes); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 13.2 TPM_SHA1Update rev 114 + + This capability inputs complete blocks of data into a pending SHA-1 digest. At the end of the + process, the digest remains pending. +*/ + +TPM_RESULT TPM_Process_SHA1Update(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_SIZED_BUFFER hashData; /* Bytes to be hashed */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SHA1Update: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&hashData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* load hashData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&hashData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1Update: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This command SHALL incorporate complete blocks of data into the digest of an existing SHA-1 + thread. Only integral numbers of complete blocks (64 bytes each) can be processed. + */ + /* 1. If there is no existing SHA-1 thread, return TPM_SHA_THREAD */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->sha1_context == NULL) { + printf("TPM_Process_SHA1Update: Error, no existing SHA1 thread\n"); + returnCode = TPM_SHA_THREAD; + } + } + /* 2. If numBytes is not a multiple of 64 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SHA1Update: numBytes %u bytes\n", hashData.size); + if ((hashData.size % 64) != 0) { + printf("TPM_Process_SHA1Update: Error, numBytes not integral number of blocks\n"); + /* a. Return TPM_SHA_ERROR */ + returnCode = TPM_SHA_ERROR; + /* b. The TPM MAY terminate the SHA-1 thread */ + TPM_SHA1Delete(&(tpm_state->sha1_context)); + } + } + /* 3. If numBytes is greater than maxNumBytes returned by TPM_SHA1Start */ + if (returnCode == TPM_SUCCESS) { + if (hashData.size > TPM_SHA1_MAXNUMBYTES) { + /* a. Return TPM_SHA_ERROR */ + returnCode = TPM_SHA_ERROR; + /* b. The TPM MAY terminate the SHA-1 thread */ + TPM_SHA1Delete(&(tpm_state->sha1_context)); + } + } + /* 4. Incorporate hashData into the digest of the existing SHA-1 thread. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1UpdateCmd(tpm_state->sha1_context, hashData.buffer, hashData.size); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1Update: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&hashData); /* @1 */ + return rcf; +} + +/* 13.3 TPM_SHA1Complete rev 87 + + This capability terminates a pending SHA-1 calculation. +*/ + +TPM_RESULT TPM_Process_SHA1Complete(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_SIZED_BUFFER hashData; /* Final bytes to be hashed */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST hashValue; /* The output of the SHA-1 hash. */ + TPM_SizedBuffer_Init(&hashData); /* freed @1 */ + + printf("TPM_Process_SHA1Complete: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* load hashData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&hashData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1Complete: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This command SHALL incorporate a partial or complete block of data into the digest of an + existing SHA-1 thread, and terminate that thread. hashDataSize MAY have values in the range + of 0 through 64, inclusive. If the SHA-1 thread has received no bytes the TPM SHALL + calculate the SHA-1 of the empty buffer. + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1CompleteCommon(hashValue, + &(tpm_state->sha1_context), + &hashData); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1Complete: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append hashValue */ + returnCode = TPM_Digest_Store(response, hashValue); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&hashData); /* @1 */ + return rcf; +} + +/* 13.4 TPM_SHA1CompleteExtend rev 109 + + This capability terminates a pending SHA-1 calculation and EXTENDS the result into a Platform + Configuration Register using a SHA-1 hash process. + + This command is designed to complete a hash sequence and extend a PCR in memory-less + environments. + + This command SHALL incorporate a partial or complete block of data into the digest of an existing + SHA-1 thread, EXTEND the resultant digest into a PCR, and terminate the thread. hashDataSize MAY + have values in the range of 0 through 64, inclusive. +*/ + +TPM_RESULT TPM_Process_SHA1CompleteExtend(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_PCRINDEX pcrNum; /* Index of the PCR to be modified */ + TPM_SIZED_BUFFER hashData; /* Final bytes to be hashed */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST h1HashValue; /* The output of the SHA-1 hash. */ + TPM_PCRVALUE outDigest; /* The PCR value after execution of the command. */ + + printf("TPM_Process_SHA1CompleteExtend: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&hashData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pcrNum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&pcrNum, &command, ¶mSize); + } + /* get hashData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SHA1CompleteExtend: pcrNum %u\n", pcrNum); + returnCode = TPM_SizedBuffer_Load(&hashData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1CompleteExtend: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. 1.Validate that pcrNum represents a legal PCR number. On error, return TPM_BADINDEX. */ + /* 2. Map V1 to TPM_STANY_DATA */ + /* 3. Map L1 to V1 -> localityModifier */ + /* 4. If the current locality, held in L1, is not selected in TPM_PERMANENT_DATA -> pcrAttrib + [PCRIndex]. pcrExtendLocal, return TPM_BAD_LOCALITY */ + /* NOTE Done in TPM_ExtendCommon() */ + /* 5. Create H1 the TPM_DIGEST of the SHA-1 session ensuring that hashData, if any, is */ + /* added to the SHA-1 session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1CompleteCommon(h1HashValue, + &(tpm_state->sha1_context), + &hashData); + } + /* 6. Perform the actions of TPM_Extend using H1 as the data and pcrNum as the PCR to extend */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ExtendCommon(outDigest, tpm_state, ordinal, pcrNum, h1HashValue); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1CompleteExtend: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append hashValue */ + returnCode = TPM_Digest_Store(response, h1HashValue); + } + /* append outDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, outDigest); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&hashData); /* @1 */ + return rcf; +} + +/* TPM_SHA1CompleteCommon() is common code for TPM_Process_SHA1Complete() and + TPM_Process_SHA1CompleteExtend() +*/ + +TPM_RESULT TPM_SHA1CompleteCommon(TPM_DIGEST hashValue, /* output: digest */ + void **sha1_context, /* IO: SHA1 context */ + TPM_SIZED_BUFFER *hashData) /* final data to be hashed */ +{ + TPM_RESULT rc = 0; + + /* The TPM specification says that the last data chunk must be 0-64 bytes */ + printf("TPM_SHA1CompleteCommon: %u bytes\n", hashData->size); + if (rc == 0) { + if (hashData->size > 64) { + printf("TPM_SHA1CompleteCommon: Error, hashDataSize %u not 0-64\n", + hashData->size); + rc = TPM_SHA_ERROR; + } + } + /* cannot call SHA1Complete() before SHA1Start() */ + if (rc == 0) { + if (*sha1_context == NULL) { + printf("TPM_SHA1CompleteCommon: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + } + if ((rc == 0) && (hashData->size != 0)) { + rc = TPM_SHA1UpdateCmd(*sha1_context, hashData->buffer, hashData->size); + } + if (rc == 0) { + rc = TPM_SHA1FinalCmd(hashValue, *sha1_context); + } + /* the SHA1 thread should be terminated even if there is an error */ + TPM_SHA1Delete(sha1_context); + return rc; +} + +/* 13.6 TPM_GetRandom rev 87 + + GetRandom returns the next bytesRequested bytes from the random number generator to the caller. + + It is recommended that a TPM implement the RNG in a manner that would allow it to return RNG + bytes such that the frequency of bytesRequested being more than the number of bytes available is + an infrequent occurrence. +*/ + +TPM_RESULT TPM_Process_GetRandom(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 */ + uint32_t bytesRequested; /* Number of bytes to return */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER randomBytes; /* The returned bytes */ + + printf("TPM_Process_GetRandom: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&randomBytes); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get bytesRequested parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&bytesRequested, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetRandom: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM determines if amount bytesRequested is available from the TPM. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetRandom: bytesRequested %u\n", bytesRequested); + if (bytesRequested > TPM_RANDOM_MAX) { + bytesRequested = TPM_RANDOM_MAX; + printf("TPM_Process_GetRandom: bytes available %u\n", bytesRequested); + } + } + /* 2. Set randomBytesSize to the number of bytes available from the RNG. This number MAY be less + than bytesRequested. */ + if ((returnCode == TPM_SUCCESS) && (bytesRequested > 0)) { + returnCode = TPM_SizedBuffer_Allocate(&randomBytes, bytesRequested); + } + /* 3. Set randomBytes to the next randomBytesSize bytes from the RNG */ + if ((returnCode == TPM_SUCCESS) && (bytesRequested > 0)) { + returnCode = TPM_Random(randomBytes.buffer, bytesRequested); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetRandom: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append randomBytes */ + returnCode = TPM_SizedBuffer_Store(response, &randomBytes); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&randomBytes); /* freed @1 */ + return rcf; +} + +/* 13.7 TPM_StirRandom rev 109 + + StirRandom adds entropy to the RNG state. +*/ + +TPM_RESULT TPM_Process_StirRandom(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_SIZED_BUFFER inData; /* Data to add entropy to RNG state, + Number of bytes of input */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_StirRandom: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_StirRandom: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If dataSize is not less than 256 bytes, the TPM MAY return TPM_BAD_PARAMETER. */ + /* The TPM updates the state of the current RNG using the appropriate mixing function. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StirRandomCmd(&inData); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_StirRandom: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inData); /* @1 */ + return rcf; +} + +/* 13.8 TPM_CertifyKey rev 107 + + The TPM_CertifyKey operation allows one key to certify the public portion of another key. A TPM + identity key may be used to certify non-migratable keys but is not permitted to certify migratory + keys or certified migration keys. As such, it allows the TPM to make the statement "this key is + held in a TPM-shielded location, and it will never be revealed." For this statement to have + veracity, the Challenger must trust the policies used by the entity that issued the identity and + the maintenance policy of the TPM manufacturer. + + Signing and legacy keys may be used to certify both migratable and non-migratable keys. Then the + usefulness of a certificate depends on the trust in the certifying key by the recipient of the + certificate. + + The key to be certified must be loaded before TPM_CertifyKey is called. + + The determination to use the TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 on the output is based on + which PCRs and what localities the certified key is restricted to. A key to be certified that + does not have locality restrictions and which uses no PCRs greater than PCR #15 will cause this + command to return and sign a TPM_CERTIFY_INFO structure, which provides compatibility with V1.1 + TPMs. + + When this command is run to certify all other keys (those that use PCR #16 or higher, as well as + those limited by locality in any way), it will return and sign a TPM_CERTIFY_INFO2 structure. + + TPM_CertifyKey does not support the case where (a) the certifying key requires a usage + authorization to be provided but (b) the key-to-be-certified does not. In such cases, + TPM_CertifyKey2 must be used. + + If a command tag (in the parameter array) specifies only one authorisation session, then the TPM + convention is that the first session listed is ignored (authDataUsage must be TPM_AUTH_NEVER for + this key) and the incoming session data is used for the second auth session in the list. In + TPM_CertifyKey, the first session is the certifying key and the second session is the + key-to-be-certified. In TPM_CertifyKey2, the first session is the key-to-be-certified and the + second session is the certifying key. +*/ + +TPM_RESULT TPM_Process_CertifyKey(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 certHandle; /* Handle of the key to be used to certify the key. */ + TPM_KEY_HANDLE keyHandle; /* Handle of the key to be certified. */ + TPM_NONCE antiReplay; /* 160 bits of externally supplied data (typically a nonce + provided to prevent replay-attacks) */ + TPM_AUTHHANDLE certAuthHandle; /* The authorization session handle used for certHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with certAuthHandle + */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA certAuth; /* The authorization session digest for inputs and + certHandle. HMAC key: certKey.auth. */ + TPM_AUTHHANDLE keyAuthHandle; /* The authorization session handle used for the key to be + signed. */ + TPM_NONCE keynonceOdd; /* Nonce generated by system associated with keyAuthHandle + */ + TPM_BOOL continueKeySession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA keyAuth; /* The authorization session digest for the inputs and key + to be signed. 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_AUTH_SESSION_DATA *cert_auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *target_auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL certAuthHandleValid = FALSE; + TPM_BOOL keyAuthHandleValid = FALSE; + TPM_SECRET *certHmacKey; + TPM_SECRET *targetHmacKey; + TPM_BOOL certPCRStatus; + TPM_BOOL targetPCRStatus; + TPM_KEY *certKey = NULL; /* the key specified by certHandle */ + TPM_KEY *targetKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *certKeyUsageAuth; + TPM_SECRET *targetKeyUsageAuth; + TPM_BOOL pcrUsage; + TPM_LOCALITY_SELECTION localityAtRelease; + int v1Version; /* TPM 1.1 or TPM 1.2 */ + int certifyType = 0; /* TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 */ + TPM_DIGEST m1Digest; /* digest of certifyInfo */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CERTIFY_INFO certifyInfo; /* TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 structure + that provides information relative to keyhandle + NOTE This is c1 in the Actions. */ + TPM_CERTIFY_INFO2 certifyInfo2; + TPM_SIZED_BUFFER outData; /* The signature of certifyInfo */ + + printf("TPM_Process_CertifyKey: Ordinal Entry\n"); + TPM_CertifyInfo_Init(&certifyInfo); /* freed @1 */ + TPM_CertifyInfo2_Init(&certifyInfo2); /* freed @2 */ + TPM_SizedBuffer_Init(&outData); /* freed @3 */ + /* + get inputs + */ + /* get certHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&certHandle, &command, ¶mSize); + } + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: certHandle %08x\n", certHandle); + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + 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_CheckRequestTag210(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&certAuthHandle, + &certAuthHandleValid, + nonceOdd, + &continueAuthSession, + certAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_CertifyKey: certAuthHandle %08x\n", certAuthHandle); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Get(&keyAuthHandle, + &keyAuthHandleValid, + keynonceOdd, + &continueKeySession, + keyAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + printf("TPM_Process_CertifyKey: keyAuthHandle %08x\n", keyAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CertifyKey: 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) { + certAuthHandleValid = FALSE; + keyAuthHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the certHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&certKey, &certPCRStatus, tpm_state, certHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&targetKey, &targetPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* 1. The TPM validates that the key pointed to by certHandle has a signature scheme of + TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO */ + if (returnCode == TPM_SUCCESS) { + if ((certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_CertifyKey: Error, invalid certKey sigScheme %04hx\n", + certKey->algorithmParms.sigScheme); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* 2. Verify command and key AuthData values */ + /* a. If tag is TPM_TAG_RQU_AUTH2_COMMAND */ + /* i. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTHFAIL on error */ + /* ii. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTH2FAIL on error */ + /* b. else if tag is TPM_TAG_RQU_AUTH1_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + /* ii. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTHFAIL on error */ + /* c. else if tag is TPM_TAG_RQU_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + /* ii. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key + referenced by keyHandle, return TPM_AUTHFAIL on error. */ + + /* NOTE: Simplified the above logic as follows */ + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND, process the first set of authorization data */ + /* get certHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&certKeyUsageAuth, certKey); + } + /* get the first session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&cert_auth_session_data, + &certHmacKey, + tpm_state, + certAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + certKey, + certKeyUsageAuth, /* OIAP */ + certKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTHFAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *certHmacKey, /* HMAC key */ + inParamDigest, + cert_auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + certAuth); /* Authorization digest for input */ + } + /* If tag is not TPM_TAG_RQU_AUTH2_COMMAND */ + /* Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (certKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CertifyKey: Error, cert key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND or TPM_TAG_RQU_AUTH1_COMMAND process the second set of + authorization data */ + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&targetKeyUsageAuth, targetKey); + } + /* get the second session data */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&target_auth_session_data, + &targetHmacKey, + tpm_state, + keyAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + targetKey, + targetKeyUsageAuth, /* OIAP */ + targetKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTH2FAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Auth2data_Check(tpm_state, + *targetHmacKey, /* HMAC key */ + inParamDigest, + target_auth_session_data, /* authorization session */ + keynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueKeySession, + keyAuth); /* Authorization digest for input */ + } + /* Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced + by keyHandle, return TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (targetKey->authDataUsage == TPM_AUTH_ALWAYS) { + printf("TPM_Process_CertifyKey: Error, target key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 3. If keyHandle -> payload is not TPM_PT_ASYM, return TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (targetKey->tpm_store_asymkey->payload != TPM_PT_ASYM) { + printf("TPM_Process_CertifyKey: Error, target key invalid payload %02x\n", + targetKey->tpm_store_asymkey->payload); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. If the key pointed to by certHandle is an identity key (certHandle -> keyUsage is + TPM_KEY_IDENTITY) */ + if ((returnCode == TPM_SUCCESS) && (certKey->keyUsage == TPM_KEY_IDENTITY)) { + /* a. If keyHandle -> keyflags -> keyInfo -> migratable is TRUE return TPM_MIGRATEFAIL */ + if (targetKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_CertifyKey: Error, target key is migratable\n"); + returnCode = TPM_MIGRATEFAIL; + } + } + /* 5. Validate that certHandle -> keyUsage is TPM_KEY_SIGN, TPM_KEY_IDENTITY or TPM_KEY_LEGACY, + if not return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: certHandle -> keyUsage %04hx\n", certKey->keyUsage); + if ((certKey->keyUsage != TPM_KEY_SIGNING) && + ((certKey->keyUsage) != TPM_KEY_IDENTITY) && + ((certKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey: Error, certHandle -> keyUsage %04hx is invalid\n", + certKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. Validate that keyHandle -> keyUsage is TPM_KEY_SIGN, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, + TPM_KEY_BIND or TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: keyHandle -> keyUsage %04hx\n", targetKey->keyUsage); + if ((targetKey->keyUsage != TPM_KEY_SIGNING) && + ((targetKey->keyUsage) != TPM_KEY_STORAGE) && + ((targetKey->keyUsage) != TPM_KEY_IDENTITY) && + ((targetKey->keyUsage) != TPM_KEY_BIND) && + ((targetKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey: Error, keyHandle -> keyUsage %04hx is invalid\n", + targetKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 7. If keyHandle -> digestAtRelease requires the use of PCRs 16 or higher to calculate or if + keyHandle -> localityAtRelease is not 0x1F */ + /* get PCR usage 16 and higher */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetPCRUsage(&pcrUsage, targetKey, 2); + } + /* get localityAtRelease */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetLocalityAtRelease(&localityAtRelease, targetKey); + } + if (returnCode == TPM_SUCCESS) { + if (pcrUsage || (localityAtRelease != TPM_LOC_ALL)) { + /* a. Set V1 to 1.2 */ + v1Version = 2; /* locality or >2 PCR's */ + } + /* 8. Else */ + else { + /* a. Set V1 to 1.1 */ + v1Version = 1; /* no locality and <= 2 PCR's */ + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: V1 %d\n", v1Version); + /* 9. If keyHandle -> pcrInfoSize is not 0 */ + if (targetKey->pcrInfo.size != 0) { + printf("TPM_Process_CertifyKey: Setting PCR info from key\n"); + /* 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 on error TPM_BAD_LOCALITY */ + /* NOTE: Done by TPM_KeyHandleEntries_GetKey() */ + /* b. If V1 is 1.1 */ + if (v1Version == 1) { + certifyType = 1; + /* i. Create C1 a TPM_CERTIFY_INFO structure */ + /* NOTE: Done by TPM_CertifyInfo_Init() */ + /* ii. Fill in C1 with the information from the key pointed to by keyHandle */ + /* NOTE: Done in common _Set() code below */ + /* iii. The TPM MUST set c1 -> pcrInfoSize to 44. */ + /* iv. The TPM MUST set c1 -> pcrInfo to a TPM_PCR_INFO structure properly filled + out using the information from keyHandle. */ + /* This function actually creates the cache, which is serialized later */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfo_CreateFromKey(&(certifyInfo.tpm_pcr_info), + targetKey); + } + /* v. The TPM MUST set c1 -> digestAtCreation to 20 bytes of 0x00. */ + if (returnCode == TPM_SUCCESS) { + TPM_Digest_Init(certifyInfo.tpm_pcr_info->digestAtCreation); + } + } + /* c. Else */ + else { + certifyType = 2; + /* i. Create C1 a TPM_CERTIFY_INFO2 structure */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + /* ii. Fill in C1 with the information from the key pointed to by keyHandle */ + /* NOTE: Done in common _Set() code below */ + /* iii. Set C1 -> pcrInfoSize to the size of an appropriate TPM_PCR_INFO_SHORT + structure. */ + /* iv. Set C1 -> pcrInfo to a properly filled out TPM_PCR_INFO_SHORT structure, + using the information from keyHandle. */ + /* This function actually creates the cache, which is serialized later */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoShort_CreateFromKey(&(certifyInfo2.tpm_pcr_info_short), + targetKey); + } + /* v. Set C1 -> migrationAuthoritySize to 0 */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + } + } + /* 10. Else */ + else { + certifyType = 1; + /* a. Create C1 a TPM_CERTIFY_INFO structure */ + /* NOTE: Done by TPM_CertifyInfo_Init() */ + /* b. Fill in C1 with the information from the key pointed to be keyHandle */ + /* NOTE: Done in common _Set() code below */ + /* c. The TPM MUST set c1 -> pcrInfoSize to 0 */ + /* NOTE: Done by TPM_CertifyInfo_Init() */ + } + } + /* 11. Create TPM_DIGEST H1 which is the SHA-1 hash of keyHandle -> pubKey -> key. Note that + <key> is the actual public modulus, and does not include any structure formatting. */ + /* 12. Set C1 -> pubKeyDigest to H1 */ + /* NOTE: Done by TPM_CertifyInfo_Set() or TPM_CertifyInfo2_Set() */ + /* 13. The TPM copies the antiReplay parameter to c1 -> data. */ + /* Set C1 -> parentPCRStatus to the value from keyHandle NOTE: Implied in specification */ + /* Fill in C1 with the information from the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: Setting certifyInfo from target key\n"); + if (certifyType == 1) { + TPM_Digest_Copy(certifyInfo.data, antiReplay); + certifyInfo.parentPCRStatus = targetPCRStatus; + returnCode = TPM_CertifyInfo_Set(&certifyInfo, targetKey); + } + else { + TPM_Digest_Copy(certifyInfo2.data, antiReplay); + certifyInfo2.parentPCRStatus = targetPCRStatus; + returnCode = TPM_CertifyInfo2_Set(&certifyInfo2, targetKey); + } + } + /* 14. The TPM sets certifyInfo to C1. */ + /* NOTE Created as certifyInfo or certifyInfo2 */ + /* 15. The TPM creates m1, a message digest formed by taking the SHA-1 of c1. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: Digesting certifyInfo\n"); + if (certifyType == 1) { + returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo, + (TPM_STORE_FUNCTION_T)TPM_CertifyInfo_Store); + } + else { + returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo2, + (TPM_STORE_FUNCTION_T)TPM_CertifyInfo2_Store); + } + } + /* a. The TPM then computes a signature using certHandle -> sigScheme. The resulting signed blob + is returned in outData. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: Signing certifyInfo digest with certifying key\n"); + returnCode = TPM_RSASignToSizedBuffer(&outData, /* signature */ + m1Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + certKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CertifyKey: 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 certifyInfo */ + if (certifyType == 1) { + returnCode = TPM_CertifyInfo_Store(response, &certifyInfo); + } + else { + returnCode = TPM_CertifyInfo2_Store(response, &certifyInfo2); + } + } + if (returnCode == TPM_SUCCESS) { + /* Return outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* 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, + *certHmacKey, /* HMAC key */ + cert_auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *targetHmacKey, /* HMAC key */ + target_auth_session_data, + outParamDigest, + keynonceOdd, + continueKeySession); + } + /* 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)) || + !continueKeySession) && + keyAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, keyAuthHandle); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + certAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, certAuthHandle); + } + /* + cleanup + */ + TPM_CertifyInfo_Delete(&certifyInfo); /* @1 */ + TPM_CertifyInfo2_Delete(&certifyInfo2); /* @2 */ + TPM_SizedBuffer_Delete(&outData); /* @3 */ + return rcf; +} + +/* 13.9 TPM_CertifyKey2 rev 107 + + This command is based on TPM_CertifyKey, but includes the ability to certify a Certifiable + Migration Key (CMK), which requires extra input parameters. + + TPM_CertifyKey2 always produces a TPM_CERTIFY_INFO2 structure. + + TPM_CertifyKey2 does not support the case where (a) the key-to-be-certified requires a usage + authorization to be provided but (b) the certifying key does not. + + If a command tag (in the parameter array) specifies only one authorisation session, then the TPM + convention is that the first session listed is ignored (authDataUsage must be + TPM_NO_READ_PUBKEY_AUTH or TPM_AUTH_NEVER for this key) and the incoming session data is used for + the second auth session in the list. In TPM_CertifyKey2, the first session is the key to be + certified and the second session is the certifying key. +*/ + +TPM_RESULT TPM_Process_CertifyKey2(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 the key to be certified. */ + TPM_KEY_HANDLE certHandle; /* Handle of the key to be used to certify the key. */ + TPM_DIGEST migrationPubDigest; /* The digest of a TPM_MSA_COMPOSITE structure, + containing at least one public key of a Migration + Authority */ + TPM_NONCE antiReplay; /* 160 bits of externally supplied data (typically a nonce + provided to prevent replay-attacks) */ + TPM_AUTHHANDLE keyAuthHandle; /* The authorization session handle used for the key to be + signed. */ + TPM_NONCE keynonceOdd; /* Nonce generated by system associated with keyAuthHandle + */ + TPM_BOOL continueKeySession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA keyAuth; /* The authorization session digest for the inputs and key + to be signed. HMAC key: key.usageAuth. */ + TPM_AUTHHANDLE certAuthHandle; /* The authorization session handle used for certHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with certAuthHandle + */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA certAuth; /* Authorization HMAC key: certKey.auth. */ + + /* 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_AUTH_SESSION_DATA *cert_auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *target_auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL certAuthHandleValid = FALSE; + TPM_BOOL keyAuthHandleValid = FALSE; + TPM_SECRET *certHmacKey; + TPM_SECRET *targetHmacKey; + TPM_BOOL certPCRStatus; + TPM_BOOL targetPCRStatus; + TPM_KEY *certKey = NULL; /* the key specified by certHandle */ + TPM_KEY *targetKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *certKeyUsageAuth; + TPM_SECRET *targetKeyUsageAuth; + TPM_STORE_ASYMKEY *targetStoreAsymkey; + TPM_CMK_MIGAUTH m2CmkMigauth; + TPM_BOOL hmacValid; + TPM_DIGEST migrationAuthority; + TPM_DIGEST m1Digest; /* digest of certifyInfo */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CERTIFY_INFO2 certifyInfo2; /* TPM_CERTIFY_INFO2 relative to keyHandle */ + TPM_SIZED_BUFFER outData; /* The signed public key. */ + + printf("TPM_Process_CertifyKey2: Ordinal Entry\n"); + TPM_CertifyInfo2_Init(&certifyInfo2); /* freed @1 */ + TPM_SizedBuffer_Init(&outData); /* freed @2 */ + TPM_CmkMigauth_Init(&m2CmkMigauth); /* freed @3 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* get certHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: keyHandle %08x\n", keyHandle); + returnCode = TPM_Load32(&certHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: certHandle %08x\n", certHandle); + /* get the migrationPubDigest parameter */ + returnCode = TPM_Digest_Load(migrationPubDigest, &command, ¶mSize); + } + /* get the antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + 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_CheckRequestTag210(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&keyAuthHandle, + &keyAuthHandleValid, + keynonceOdd, + &continueKeySession, + keyAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_CertifyKey2: keyAuthHandle %08x\n", keyAuthHandle); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Get(&certAuthHandle, + &certAuthHandleValid, + nonceOdd, + &continueAuthSession, + certAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + printf("TPM_Process_CertifyKey2: certAuthHandle %08x\n", certAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CertifyKey2: 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) { + certAuthHandleValid = FALSE; + keyAuthHandleValid = FALSE; + } + /* + Processing + */ + /* get the keys corresponding to the certHandle and keyHandle parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&targetKey, &targetPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&certKey, &certPCRStatus, tpm_state, certHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the TPM_STORE_ASYMKEY cache for the target TPM_KEY */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetStoreAsymkey(&targetStoreAsymkey, targetKey); + } + /* 1. The TPM validates that the key pointed to by certHandle has a signature scheme of + TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO */ + if (returnCode == TPM_SUCCESS) { + if ((certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_CertifyKey2: Error, invalid certKey sigScheme %04hx\n", + certKey->algorithmParms.sigScheme); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* 2. Verify command and key AuthData values: */ + /* a. If tag is TPM_TAG_RQU_AUTH2_COMMAND */ + /* i. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTHFAIL on error */ + /* ii. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTH2FAIL on error */ + /* b. else if tag is TPM_TAG_RQU_AUTH1_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key + referenced by keyHandle, return TPM_AUTHFAIL on error */ + /* ii. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTHFAIL on error */ + /* c. else if tag is TPM_TAG_RQU_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key + referenced by keyHandle, return TPM_AUTHFAIL on error */ + /* ii. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + /* NOTE: Simplified the above logic as follows */ + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND, process the first set of authorization data */ + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&targetKeyUsageAuth, targetKey); + } + /* get the first session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&target_auth_session_data, + &targetHmacKey, + tpm_state, + keyAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + targetKey, + targetKeyUsageAuth, /* OIAP */ + targetKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTHFAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *targetHmacKey, /* HMAC key */ + inParamDigest, + target_auth_session_data, /* authorization session */ + keynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueKeySession, + keyAuth); /* Authorization digest for input */ + } + /* If tag is not TPM_TAG_RQU_AUTH2_COMMAND */ + /* Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced + by keyHandle, return TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (targetKey->authDataUsage == TPM_AUTH_ALWAYS) { + printf("TPM_Process_CertifyKey2: Error, target key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND or TPM_TAG_RQU_AUTH1_COMMAND process the second set of + authorization data */ + /* get certHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&certKeyUsageAuth, certKey); + } + /* get the second session data */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&cert_auth_session_data, + &certHmacKey, + tpm_state, + certAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + certKey, + certKeyUsageAuth, /* OIAP */ + certKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTH2FAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Auth2data_Check(tpm_state, + *certHmacKey, /* HMAC key */ + inParamDigest, + cert_auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + certAuth); /* Authorization digest for input */ + } + /* If the command is TPM_TAG_RQU_COMMAND */ + /* Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (certKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CertifyKey2: Error, cert key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 3. If the key pointed to by certHandle is an identity key (certHandle -> keyUsage is + TPM_KEY_IDENTITY) */ + if ((returnCode == TPM_SUCCESS) && (certKey->keyUsage == TPM_KEY_IDENTITY)) { + /* a. If keyHandle -> keyFlags -> migratable is TRUE and + [keyHandle -> keyFlags-> migrateAuthority is FALSE or + (keyHandle -> payload != TPM_PT_MIGRATE_RESTRICTED and + keyHandle -> payload != TPM_PT_MIGRATE_EXTERNAL)] + return TPM_MIGRATEFAIL */ + if ((targetKey->keyFlags & TPM_MIGRATABLE) && + (!(targetKey->keyFlags & TPM_MIGRATEAUTHORITY) || + ((targetStoreAsymkey->payload != TPM_PT_MIGRATE_RESTRICTED) && + (targetStoreAsymkey->payload != TPM_PT_MIGRATE_EXTERNAL)))) { + printf("TPM_Process_CertifyKey2: Error, target key migrate fail\n"); + returnCode = TPM_MIGRATEFAIL; + } + } + /* 4. Validate that certHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or + TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: certHandle ->keyUsage %04hx\n", certKey->keyUsage); + if ((certKey->keyUsage != TPM_KEY_SIGNING) && + ((certKey->keyUsage) != TPM_KEY_IDENTITY) && + ((certKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey2: Error, keyUsage %04hx is invalid\n", + certKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, + TPM_KEY_BIND or TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: keyHandle -> keyUsage %04hx\n", targetKey->keyUsage); + if ((targetKey->keyUsage != TPM_KEY_SIGNING) && + ((targetKey->keyUsage) != TPM_KEY_STORAGE) && + ((targetKey->keyUsage) != TPM_KEY_IDENTITY) && + ((targetKey->keyUsage) != TPM_KEY_BIND) && + ((targetKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey2: Error, keyHandle -> keyUsage %04hx is invalid\n", + targetKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. The TPM SHALL create a c1 a TPM_CERTIFY_INFO2 structure from the key pointed to by + keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CertifyInfo2_Set(&certifyInfo2, targetKey); + } + /* 7. Create TPM_DIGEST H1 which is the SHA-1 hash of keyHandle -> pubKey -> key. Note that + <key> is the actual public modulus, and does not include any structure formatting. */ + /* 8. Set C1 -> pubKeyDigest to H1 */ + /* NOTE: Done by TPM_CertifyInfo2_Set() */ + if (returnCode == TPM_SUCCESS) { + /* 9. Copy the antiReplay parameter to c1 -> data */ + TPM_Digest_Copy(certifyInfo2.data, antiReplay); + /* 10. Copy other keyHandle parameters into C1 */ + certifyInfo2.parentPCRStatus = targetPCRStatus; + /* 11. If keyHandle -> payload == TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_EXTERNAL */ + if ((targetStoreAsymkey->payload == TPM_PT_MIGRATE_RESTRICTED) || + (targetStoreAsymkey->payload == TPM_PT_MIGRATE_EXTERNAL)) { + printf("TPM_Process_CertifyKey2: " + "TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_RESTRICTED\n"); + /* a. create thisPubKey, a TPM_PUBKEY structure containing the public key, algorithm and + parameters corresponding to keyHandle */ + /* NOTE Not required. Digest is created directly below */ + /* b. Verify that the migration authorization is valid for this key */ + /* i. Create M2 a TPM_CMK_MIGAUTH structure */ + /* NOTE Done by TPM_CmkMigauth_Init() */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set M2 -> msaDigest to migrationPubDigest */ + TPM_Digest_Copy(m2CmkMigauth.msaDigest, migrationPubDigest ); + /* iii. Set M2 -> pubKeyDigest to SHA-1[thisPubKey] */ + returnCode = TPM_Key_GeneratePubkeyDigest(m2CmkMigauth.pubKeyDigest, targetKey); + } + /* iv. Verify that [keyHandle -> migrationAuth] == HMAC(M2) signed by using tpmProof as + the secret and return error TPM_MA_SOURCE on mismatch */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Check migrationAuth\n"); + returnCode = + TPM_CmkMigauth_CheckHMAC(&hmacValid, /* result */ + targetStoreAsymkey->migrationAuth, /* expect */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkMigauth); + } + if (returnCode == TPM_SUCCESS) { + if (!hmacValid) { + printf("TPM_Process_CertifyKey2: Error, Invalid migrationAuth\n"); + returnCode = TPM_MA_SOURCE; + } + } + /* c. Set C1 -> migrationAuthority = SHA-1(migrationPubDigest || keyHandle -> payload) + */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Set migrationAuthority\n"); + returnCode = TPM_SHA1(migrationAuthority, + TPM_DIGEST_SIZE, migrationPubDigest, + sizeof(TPM_PAYLOAD_TYPE), &(targetStoreAsymkey->payload), + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Set(&(certifyInfo2.migrationAuthority), + TPM_DIGEST_SIZE, migrationAuthority); + } + /* d. if keyHandle -> payload == TPM_PT_MIGRATE_RESTRICTED */ + /* i. Set C1 -> payloadType = TPM_PT_MIGRATE_RESTRICTED */ + /* e. if keyHandle -> payload == TPM_PT_MIGRATE_EXTERNAL */ + /* i. Set C1 -> payloadType = TPM_PT_MIGRATE_EXTERNAL */ + /* NOTE: Done by TPM_CertifyInfo2_Set() */ + } + /* 12. Else */ + else { + printf("TPM_Process_CertifyKey2: " + " Not TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_RESTRICTED\n"); + /* a. set C1 -> migrationAuthority = NULL */ + /* b. set C1 -> migrationAuthoritySize = 0 */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + /* c. Set C1 -> payloadType = TPM_PT_ASYM */ + certifyInfo2.payloadType = TPM_PT_ASYM; + } + } + if (returnCode == TPM_SUCCESS) { + /* 13. If keyHandle -> pcrInfoSize is not 0 */ + if (targetKey->pcrInfo.size != 0) { + printf("TPM_Process_CertifyKey2: Setting PCR info from key\n"); + /* a. The TPM MUST set c1 -> pcrInfoSize to match the pcrInfoSize from the keyHandle + key. */ + /* b. The TPM MUST set c1 -> pcrInfo to match the pcrInfo from the keyHandle key */ + /* This function actually creates the cache, which is serialized later */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoShort_CreateFromKey(&(certifyInfo2.tpm_pcr_info_short), + targetKey); + } + /* c. 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 on error TPM_BAD_LOCALITY */ + /* NOTE: Done by TPM_KeyHandleEntries_GetKey() */ + } + /* 14. Else */ + /* a. The TPM MUST set c1 -> pcrInfoSize to 0 */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + } + /* 15. The TPM creates m1, a message digest formed by taking the SHA-1 of c1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Digesting certifyInfo\n"); + returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo2, + (TPM_STORE_FUNCTION_T)TPM_CertifyInfo2_Store); + } + /* a. The TPM then computes a signature using certHandle -> sigScheme. The resulting signed blob + is returned in outData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Signing certifyInfo digest\n"); + returnCode = TPM_RSASignToSizedBuffer(&outData, /* signature */ + m1Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + certKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CertifyKey2: 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 certifyInfo */ + returnCode = TPM_CertifyInfo2_Store(response, &certifyInfo2); + } + if (returnCode == TPM_SUCCESS) { + /* Return outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* 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, + *targetHmacKey, /* HMAC key */ + target_auth_session_data, + outParamDigest, + keynonceOdd, + continueKeySession); + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *certHmacKey, /* HMAC key */ + cert_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)) || + !continueKeySession) && + keyAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, keyAuthHandle); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + certAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, certAuthHandle); + } + /* + cleanup + */ + TPM_CertifyInfo2_Delete(&certifyInfo2); /* @1 */ + TPM_SizedBuffer_Delete(&outData); /* @2 */ + TPM_CmkMigauth_Delete(&m2CmkMigauth); /* @3 */ + return rcf; +} + +/* 28.3 TPM_CertifySelfTest rev 94 + + CertifySelfTest causes the TPM to perform a full self-test and return an authenticated value if + the test passes. + + If a caller itself requires proof, it is sufficient to use any signing key for which only the TPM + and the caller have AuthData. + + If a caller requires proof for a third party, the signing key must be one whose signature is + trusted by the third party. A TPM-identity key may be suitable. + + Information returned by TPM_CertifySelfTest MUST NOT aid identification of an individual TPM. +*/ + +TPM_RESULT TPM_Process_CertifySelfTest(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 + digital signatures. */ + TPM_NONCE antiReplay; /* AntiReplay nonce to prevent replay of messages */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA privAuth; /* The authorization session 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_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *sigKey; /* from keyHandle */ + TPM_BOOL sigKeyPCRStatus; + TPM_SECRET *sigKeyUsageAuth; + TPM_COMMAND_CODE nOrdinal; /* ordinal in nbo */ + TPM_DIGEST m2Digest; /* message to sign */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_CertifySelfTest: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&sig); /* 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; + /* get the antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifySelfTest: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + 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_CertifySelfTest: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. The TPM SHALL perform TPM_SelfTestFull. If the test fails the TPM returns the appropriate + error code. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifySelfTest: Running self test\n"); + returnCode = TPM_SelfTestFullCmd(tpm_state); + } + /* 2. After successful completion of the self-test the TPM then validates the authorization to + use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &sigKeyPCRStatus, 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 (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CertifySelfTest: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&sigKeyUsageAuth, sigKey); + } + /* 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, + sigKey, + sigKeyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* Validate the command parameters using privAuth */ + 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 */ + } + /* a. If the key pointed to by keyHandle has a signature scheme that is not + TPM_SS_RSASSAPKCS1v15_SHA1, the TPM may either return TPM_BAD_SCHEME or may return + TPM_SUCCESS and a vendor specific signature. */ + if (returnCode == TPM_SUCCESS) { + if (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_Process_CertifySelfTest: Error, invalid sigKey sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_BAD_SCHEME; + } + } + /* The key in keyHandle MUST have a KEYUSAGE value of type TPM_KEY_SIGNING or TPM_KEY_LEGACY or + TPM_KEY_IDENTITY. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + (sigKey->keyUsage != TPM_KEY_LEGACY) && + (sigKey->keyUsage != TPM_KEY_IDENTITY)) { + printf("TPM_Process_CertifySelfTest: Error, Illegal keyUsage %04hx\n", + sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Create t1 the NOT null terminated string of "Test Passed" */ + /* 4. The TPM creates m2 the message to sign by concatenating t1 || AntiReplay || ordinal. */ + if (returnCode == TPM_SUCCESS) { + nOrdinal = htonl(ordinal); + returnCode = TPM_SHA1(m2Digest, + sizeof("Test Passed") - 1, "Test Passed", + TPM_NONCE_SIZE, antiReplay, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + 0, NULL); + } + /* 5. The TPM signs the SHA-1 of m2 using the key identified by keyHandle, and returns the + signature as sig. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifySelfTest: Signing certifyInfo digest\n"); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + m2Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CertifySelfTest: 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 sig */ + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* 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_SizedBuffer_Delete(&sig); /* @1 */ + return rcf; +} |