summaryrefslogtreecommitdiffstats
path: root/src/tpm12/tpm_cryptoh.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tpm12/tpm_cryptoh.c')
-rw-r--r--src/tpm12/tpm_cryptoh.c5427
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, &paramSize);
+ }
+ /* 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, &paramSize); /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get hashData */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_SHA1CompleteExtend: pcrNum %u\n", pcrNum);
+ returnCode = TPM_SizedBuffer_Load(&hashData, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get keyHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_CertifyKey: certHandle %08x\n", certHandle);
+ returnCode = TPM_Load32(&keyHandle, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* get certHandle parameter */
+ if (returnCode == TPM_SUCCESS) {
+ printf("TPM_Process_CertifyKey2: keyHandle %08x\n", keyHandle);
+ returnCode = TPM_Load32(&certHandle, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* get the antiReplay parameter */
+ if (returnCode == TPM_SUCCESS) {
+ returnCode = TPM_Nonce_Load(antiReplay, &command, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ /* 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, &paramSize);
+ }
+ 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;
+}