blob: 2b9916526ecb4989b29d30e369c62ee5bc6e3d75 [file] [log] [blame]
/* Software-based Trusted Platform Module (TPM) Emulator
* Copyright (C) 2004-2010 Mario Strasser <mast@gmx.net>
*
* This module is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This module is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* $Id: tpm_crypto.c 368 2010-02-15 09:26:37Z mast $
*/
#include "tpm_emulator.h"
#include "tpm_commands.h"
#include "tpm_data.h"
#include "tpm_handles.h"
#include "crypto/sha1.h"
#include "crypto/hmac.h"
#include "crypto/rc4.h"
#include "tpm_marshalling.h"
/*
* Cryptographic Functions ([TPM_Part3], Section 13)
*/
static tpm_sha1_ctx_t sha1_ctx;
static BOOL sha1_ctx_valid = FALSE;
TPM_RESULT TPM_SHA1Start(UINT32 *maxNumBytes)
{
info("TPM_SHA1Start()");
tpm_sha1_init(&sha1_ctx);
sha1_ctx_valid = TRUE;
/* this limit was arbitrarily chosen */
*maxNumBytes = 2048;
return TPM_SUCCESS;
}
TPM_RESULT TPM_SHA1Update(UINT32 numBytes, BYTE *hashData)
{
info("TPM_SHA1Update()");
if (!sha1_ctx_valid) return TPM_SHA_THREAD;
tpm_sha1_update(&sha1_ctx, hashData, numBytes);
return TPM_SUCCESS;
}
TPM_RESULT TPM_SHA1Complete(UINT32 hashDataSize, BYTE *hashData,
TPM_DIGEST *hashValue)
{
info("TPM_SHA1Complete()");
if (!sha1_ctx_valid) return TPM_SHA_THREAD;
sha1_ctx_valid = FALSE;
tpm_sha1_update(&sha1_ctx, hashData, hashDataSize);
tpm_sha1_final(&sha1_ctx, hashValue->digest);
return TPM_SUCCESS;
}
TPM_RESULT TPM_SHA1CompleteExtend(TPM_PCRINDEX pcrNum, UINT32 hashDataSize,
BYTE *hashData, TPM_DIGEST *hashValue,
TPM_PCRVALUE *outDigest)
{
TPM_RESULT res;
info("TPM_SHA1CompleteExtend()");
res = TPM_SHA1Complete(hashDataSize, hashData, hashValue);
if (res != TPM_SUCCESS) return res;
return TPM_Extend(pcrNum, hashValue, outDigest);
}
TPM_RESULT tpm_verify(TPM_PUBKEY_DATA *key, TPM_AUTH *auth, BOOL isInfo,
BYTE *data, UINT32 dataSize, BYTE *sig, UINT32 sigSize)
{
if (sigSize != key->key.size >> 3) return TPM_BAD_SIGNATURE;
if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) {
/* use signature scheme PKCS1_SHA1_RAW */
if (dataSize != 20) return TPM_BAD_PARAMETER;
if (tpm_rsa_verify(&key->key, RSA_SSA_PKCS1_SHA1_RAW,
data, dataSize, sig) != 0) return TPM_BAD_SIGNATURE;
} else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_DER) {
/* use signature scheme PKCS1_DER */
if ((dataSize + 11) > (UINT32)(key->key.size >> 3)
|| dataSize == 0) return TPM_BAD_PARAMETER;
if (tpm_rsa_verify(&key->key, RSA_SSA_PKCS1_DER,
data, dataSize, sig) != 0) return TPM_BAD_SIGNATURE;
} else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO && !isInfo) {
/* use signature scheme PKCS1_SHA1 and TPM_SIGN_INFO container */
BYTE buf[dataSize + 30];
if ((dataSize + 30) > (UINT32)(key->key.size >> 3)
|| dataSize == 0) return TPM_BAD_PARAMETER;
/* setup TPM_SIGN_INFO structure */
memcpy(&buf[0], "\x00\x05SIGN", 6);
memcpy(&buf[6], auth->nonceOdd.nonce, 20);
buf[26] = (dataSize >> 24) & 0xff;
buf[27] = (dataSize >> 16) & 0xff;
buf[28] = (dataSize >> 8) & 0xff;
buf[29] = (dataSize ) & 0xff;
memcpy(&buf[30], data, dataSize);
if (tpm_rsa_verify(&key->key, RSA_SSA_PKCS1_SHA1,
data, dataSize, sig) != 0) return TPM_BAD_SIGNATURE;
} else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO && isInfo) {
/* TPM_SIGN_INFO structure is already set up */
if (dataSize > (UINT32)(key->key.size >> 3)
|| dataSize == 0) return TPM_BAD_PARAMETER;
if (tpm_rsa_verify(&key->key, RSA_SSA_PKCS1_SHA1,
data, dataSize, sig) != 0) return TPM_BAD_SIGNATURE;
} else {
return TPM_INVALID_KEYUSAGE;
}
return TPM_SUCCESS;
}
TPM_RESULT tpm_sign(TPM_KEY_DATA *key, TPM_AUTH *auth, BOOL isInfo,
BYTE *areaToSign, UINT32 areaToSignSize,
BYTE **sig, UINT32 *sigSize)
{
if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) {
/* use signature scheme PKCS1_SHA1_RAW */
if (areaToSignSize != 20) return TPM_BAD_PARAMETER;
*sigSize = key->key.size >> 3;
*sig = tpm_malloc(*sigSize);
if (*sig == NULL || tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_SHA1_RAW,
areaToSign, areaToSignSize, *sig)) {
tpm_free(*sig);
return TPM_FAIL;
}
} else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_DER) {
/* use signature scheme PKCS1_DER */
if ((areaToSignSize + 11) > (UINT32)(key->key.size >> 3)
|| areaToSignSize == 0) return TPM_BAD_PARAMETER;
*sigSize = key->key.size >> 3;
*sig = tpm_malloc(*sigSize);
if (*sig == NULL || tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_DER,
areaToSign, areaToSignSize, *sig)) {
tpm_free(*sig);
return TPM_FAIL;
}
} else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO && !isInfo) {
/* use signature scheme PKCS1_SHA1 and TPM_SIGN_INFO container */
BYTE buf[areaToSignSize + 30];
if ((areaToSignSize + 30) > (UINT32)(key->key.size >> 3)
|| areaToSignSize == 0) return TPM_BAD_PARAMETER;
*sigSize = key->key.size >> 3;
*sig = tpm_malloc(*sigSize);
if (*sig == NULL) return TPM_FAIL;
/* setup TPM_SIGN_INFO structure */
memcpy(&buf[0], "\x00\x05SIGN", 6);
memcpy(&buf[6], auth->nonceOdd.nonce, 20);
buf[26] = (areaToSignSize >> 24) & 0xff;
buf[27] = (areaToSignSize >> 16) & 0xff;
buf[28] = (areaToSignSize >> 8) & 0xff;
buf[29] = (areaToSignSize ) & 0xff;
memcpy(&buf[30], areaToSign, areaToSignSize);
if (tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_SHA1,
buf, areaToSignSize + 30, *sig)) {
tpm_free(*sig);
return TPM_FAIL;
}
} else if (key->sigScheme == TPM_SS_RSASSAPKCS1v15_INFO && isInfo) {
/* TPM_SIGN_INFO structure is already set up */
if (areaToSignSize > (UINT32)(key->key.size >> 3)
|| areaToSignSize == 0) return TPM_BAD_PARAMETER;
*sigSize = key->key.size >> 3;
*sig = tpm_malloc(*sigSize);
if (*sig == NULL) return TPM_FAIL;
if (tpm_rsa_sign(&key->key, RSA_SSA_PKCS1_SHA1,
areaToSign, areaToSignSize, *sig)) {
tpm_free(*sig);
return TPM_FAIL;
}
} else {
return TPM_INVALID_KEYUSAGE;
}
return TPM_SUCCESS;
}
TPM_RESULT TPM_Sign(TPM_KEY_HANDLE keyHandle, UINT32 areaToSignSize,
BYTE *areaToSign, TPM_AUTH *auth1,
UINT32 *sigSize, BYTE **sig)
{
TPM_RESULT res;
TPM_KEY_DATA *key;
info("TPM_Sign()");
/* get key */
key = tpm_get_key(keyHandle);
if (key == NULL) return TPM_INVALID_KEYHANDLE;
/* verify authorization */
if (auth1->authHandle != TPM_INVALID_HANDLE
|| key->authDataUsage != TPM_AUTH_NEVER) {
res = tpm_verify_auth(auth1, key->usageAuth, keyHandle);
if (res != TPM_SUCCESS) return res;
}
if (key->keyUsage != TPM_KEY_SIGNING && key->keyUsage != TPM_KEY_LEGACY)
return TPM_INVALID_KEYUSAGE;
/* sign data */
return tpm_sign(key, auth1, FALSE, areaToSign, areaToSignSize, sig, sigSize);
}
void tpm_get_random_bytes(void *buf, size_t nbytes)
{
if (tpmConf & TPM_CONF_USE_INTERNAL_PRNG) {
tpm_rc4_ctx_t ctx;
tpm_rc4_init(&ctx, tpmData.permanent.data.rngState,
sizeof(tpmData.permanent.data.rngState));
tpm_rc4_crypt(&ctx, buf, buf, nbytes);
tpm_rc4_crypt(&ctx, tpmData.permanent.data.rngState,
tpmData.permanent.data.rngState, sizeof(tpmData.permanent.data.rngState));
} else {
tpm_get_extern_random_bytes(buf, nbytes);
}
}
TPM_RESULT TPM_GetRandom(UINT32 bytesRequested, UINT32 *randomBytesSize,
BYTE **randomBytes)
{
info("TPM_GetRandom()");
*randomBytesSize = (bytesRequested < 2048) ? bytesRequested : 2048;
*randomBytes = tpm_malloc(*randomBytesSize);
if (*randomBytes == NULL) return TPM_SIZE;
tpm_get_random_bytes(*randomBytes, *randomBytesSize);
return TPM_SUCCESS;
}
TPM_RESULT TPM_StirRandom(UINT32 dataSize, BYTE *inData)
{
info("TPM_StirRandom()");
UINT32 i, length = sizeof(tpmData.permanent.data.rngState);
while (dataSize > length) {
for (i = 0; i < length; i++) {
tpmData.permanent.data.rngState[i] ^= *inData++;
}
dataSize -= length;
}
for (i = 0; i < dataSize; i++) {
tpmData.permanent.data.rngState[i] ^= *inData++;
}
return TPM_SUCCESS;
}
TPM_RESULT TPM_CertifyKey(TPM_KEY_HANDLE certHandle, TPM_KEY_HANDLE keyHandle,
TPM_NONCE *antiReplay, TPM_AUTH *auth1,
TPM_AUTH *auth2, TPM_CERTIFY_INFO *certifyInfo,
UINT32 *outDataSize, BYTE **outData)
{
TPM_RESULT res;
TPM_KEY_DATA *cert, *key;
tpm_sha1_ctx_t sha1_ctx;
BYTE *buf, *p;
UINT32 length;
info("TPM_CertifyKey()");
/* get keys */
cert = tpm_get_key(certHandle);
if (cert == NULL) return TPM_INVALID_KEYHANDLE;
key = tpm_get_key(keyHandle);
if (key == NULL) return TPM_INVALID_KEYHANDLE;
/* verify authorization */
if (auth2->authHandle != TPM_INVALID_HANDLE
|| cert->authDataUsage != TPM_AUTH_NEVER) {
res = tpm_verify_auth(auth1, cert->usageAuth, certHandle);
if (res != TPM_SUCCESS) return res;
}
if (auth1->authHandle != TPM_INVALID_HANDLE
|| key->authDataUsage != TPM_AUTH_NEVER) {
res = tpm_verify_auth(auth2, key->usageAuth, keyHandle);
if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res;
}
/* verify key usage */
if (cert->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1
&& cert->sigScheme != TPM_SS_RSASSAPKCS1v15_INFO) return TPM_BAD_SCHEME;
if (cert->keyUsage == TPM_KEY_IDENTITY
&& (key->keyFlags & TPM_KEY_FLAG_MIGRATABLE)
&& !(key->keyFlags & TPM_KEY_FLAG_AUTHORITY)) return TPM_MIGRATEFAIL;
if (key->keyFlags & TPM_KEY_FLAG_HAS_PCR) {
if (!(key->keyFlags & TPM_KEY_FLAG_PCR_IGNORE)) {
TPM_DIGEST digest;
res = tpm_compute_pcr_digest(&key->pcrInfo.releasePCRSelection,
&digest, NULL);
if (res != TPM_SUCCESS) return res;
if (memcmp(&digest, &key->pcrInfo.digestAtRelease, sizeof(TPM_DIGEST)))
return TPM_WRONGPCRVAL;
if (key->pcrInfo.tag == TPM_TAG_PCR_INFO_LONG
&& !(key->pcrInfo.localityAtRelease
& (1 << tpmData.stany.flags.localityModifier)))
return TPM_BAD_LOCALITY;
}
/* if sizeOfSelect is two use a TPM_CERTIFY_INFO structure ... */
if (key->pcrInfo.releasePCRSelection.sizeOfSelect == 2) {
certifyInfo->tag = 0x0101;
certifyInfo->fill = 0x0000;
certifyInfo->migrationAuthoritySize = 0;
memcpy(&certifyInfo->PCRInfo, &key->pcrInfo, sizeof(TPM_PCR_INFO));
memset(&certifyInfo->PCRInfo.digestAtCreation, 0, sizeof(TPM_DIGEST));
certifyInfo->PCRInfoSize = sizeof(TPM_PCR_INFO);
/* ... otherwise use a TPM_CERTIFY_INFO2 structure */
} else {
certifyInfo->tag = TPM_TAG_CERTIFY_INFO2;
certifyInfo->fill = 0x0000;
certifyInfo->migrationAuthoritySize = 0;
memcpy(&certifyInfo->PCRInfo, &key->pcrInfo, sizeof(TPM_PCR_INFO));
certifyInfo->PCRInfoSize = sizeof(TPM_PCR_INFO);
}
} else {
/* setup TPM_CERTIFY_INFO structure */
certifyInfo->tag = 0x0101;
certifyInfo->fill = 0x0000;
certifyInfo->migrationAuthoritySize = 0;
certifyInfo->PCRInfoSize = 0;
}
/* setup CERTIFY_INFO[2] structure */
certifyInfo->keyUsage = key->keyUsage;
certifyInfo->keyFlags = key->keyFlags & TPM_KEY_FLAG_MASK;
certifyInfo->authDataUsage = key->authDataUsage;
certifyInfo->parentPCRStatus = key->parentPCRStatus;
if (tpm_setup_key_parms(key, &certifyInfo->algorithmParms)) return TPM_FAIL;
memcpy(&certifyInfo->data, antiReplay, sizeof(TPM_NONCE));
/* compute pubKeyDigest */
length = key->key.size >> 3;
buf = tpm_malloc(length);
if (buf == NULL) {
free_TPM_KEY_PARMS(certifyInfo->algorithmParms);
return TPM_FAIL;
}
tpm_rsa_export_modulus(&key->key, buf, NULL);
tpm_sha1_init(&sha1_ctx);
tpm_sha1_update(&sha1_ctx, buf, length);
tpm_sha1_final(&sha1_ctx, certifyInfo->pubkeyDigest.digest);
tpm_free(buf);
/* compute the digest of the CERTIFY_INFO[2] structure and sign it */
length = sizeof_TPM_CERTIFY_INFO((*certifyInfo));
p = buf = tpm_malloc(length);
if (buf == NULL
|| tpm_marshal_TPM_CERTIFY_INFO(&p, &length, certifyInfo)) {
free_TPM_KEY_PARMS(certifyInfo->algorithmParms);
return TPM_FAIL;
}
length = sizeof_TPM_CERTIFY_INFO((*certifyInfo));
tpm_sha1_init(&sha1_ctx);
tpm_sha1_update(&sha1_ctx, buf, length);
tpm_sha1_final(&sha1_ctx, buf);
res = tpm_sign(cert, auth1, FALSE, buf, SHA1_DIGEST_LENGTH, outData, outDataSize);
tpm_free(buf);
if (res != TPM_SUCCESS) {
free_TPM_KEY_PARMS(certifyInfo->algorithmParms);
return res;
}
return TPM_SUCCESS;
}
TPM_RESULT TPM_CertifyKey2(TPM_KEY_HANDLE certHandle, TPM_KEY_HANDLE keyHandle,
TPM_DIGEST *migrationPubDigest,
TPM_NONCE *antiReplay, TPM_AUTH *auth1,
TPM_AUTH *auth2, TPM_CERTIFY_INFO *certifyInfo,
UINT32 *outDataSize, BYTE **outData)
{
TPM_RESULT res;
TPM_KEY_DATA *cert, *key;
tpm_sha1_ctx_t sha1_ctx;
BYTE *buf, *p;
UINT32 length;
info("TPM_CertifyKey2()");
/* get keys */
cert = tpm_get_key(certHandle);
if (cert == NULL) return TPM_INVALID_KEYHANDLE;
key = tpm_get_key(keyHandle);
if (key == NULL) return TPM_INVALID_KEYHANDLE;
/* verify authorization */
if (auth2->authHandle != TPM_INVALID_HANDLE
|| cert->authDataUsage != TPM_AUTH_NEVER) {
res = tpm_verify_auth(auth1, cert->usageAuth, certHandle);
if (res != TPM_SUCCESS) return res;
}
if (auth1->authHandle != TPM_INVALID_HANDLE
|| key->authDataUsage != TPM_AUTH_NEVER) {
res = tpm_verify_auth(auth2, key->usageAuth, keyHandle);
if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res;
}
/* verify key usage */
if (cert->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) return TPM_BAD_SCHEME;
if (cert->keyUsage == TPM_KEY_IDENTITY
&& (key->keyFlags & TPM_KEY_FLAG_MIGRATABLE)
&& !(key->keyFlags & TPM_KEY_FLAG_AUTHORITY)) return TPM_MIGRATEFAIL;
if (key->keyFlags & TPM_KEY_FLAG_HAS_PCR) {
if (!(key->keyFlags & TPM_KEY_FLAG_PCR_IGNORE)) {
TPM_DIGEST digest;
res = tpm_compute_pcr_digest(&key->pcrInfo.releasePCRSelection,
&digest, NULL);
if (res != TPM_SUCCESS) return res;
if (memcmp(&digest, &key->pcrInfo.digestAtRelease, sizeof(TPM_DIGEST)))
return TPM_WRONGPCRVAL;
if (key->pcrInfo.tag == TPM_TAG_PCR_INFO_LONG
&& !(key->pcrInfo.localityAtRelease
& (1 << tpmData.stany.flags.localityModifier)))
return TPM_BAD_LOCALITY;
}
memcpy(&certifyInfo->PCRInfo, &key->pcrInfo, sizeof(TPM_PCR_INFO));
certifyInfo->PCRInfoSize = sizeof(certifyInfo->PCRInfo);
} else {
certifyInfo->PCRInfoSize = 0;
}
/* setup migration authority values */
if (key->payload == TPM_PT_MIGRATE_RESTRICTED
|| key->payload == TPM_PT_MIGRATE_EXTERNAL) {
TPM_PUBKEY pubKey;
TPM_DIGEST keyDigest;
BYTE buf[SHA1_DIGEST_LENGTH];
tpm_hmac_ctx_t hmac_ctx;
tpm_sha1_ctx_t sha1_ctx;
/* compute digest of public key */
if (tpm_extract_pubkey(key, &pubKey) != 0) {
debug("tpm_extract_pubkey() failed");
return TPM_FAIL;
}
if (tpm_compute_pubkey_digest(&pubKey, &keyDigest) != 0) {
debug("tpm_compute_pubkey_digest() failed.");
free_TPM_PUBKEY(pubKey);
return TPM_FAIL;
}
free_TPM_PUBKEY(pubKey);
/* verify migration authorization */
buf[0] = (TPM_TAG_CMK_MIGAUTH >> 8) & 0xff;
buf[1] = TPM_TAG_CMK_MIGAUTH & 0xff;
tpm_hmac_init(&hmac_ctx, tpmData.permanent.data.tpmProof.nonce, sizeof(TPM_NONCE));
tpm_hmac_update(&hmac_ctx, buf, 2);
tpm_hmac_update(&hmac_ctx, migrationPubDigest->digest, sizeof(TPM_DIGEST));
tpm_hmac_update(&hmac_ctx, keyDigest.digest, sizeof(TPM_DIGEST));
tpm_hmac_final(&hmac_ctx, buf);
if (memcmp(key->migrationAuth, buf, sizeof(TPM_SECRET)) != 0) return TPM_MA_SOURCE;
/* compute migrationAuthority */
certifyInfo->migrationAuthoritySize = SHA1_DIGEST_LENGTH;
certifyInfo->migrationAuthority = tpm_malloc(certifyInfo->migrationAuthoritySize);
if (certifyInfo->migrationAuthority == NULL) return TPM_NOSPACE;
tpm_sha1_init(&sha1_ctx);
tpm_sha1_update(&sha1_ctx, migrationPubDigest->digest, sizeof(TPM_DIGEST));
buf[0] = key->payload;
tpm_sha1_update(&sha1_ctx, buf, 1);
tpm_sha1_final(&sha1_ctx, certifyInfo->migrationAuthority);
certifyInfo->payloadType = key->payload;
} else {
certifyInfo->migrationAuthoritySize = 0;
certifyInfo->migrationAuthority = 0;
certifyInfo->payloadType = TPM_PT_ASYM;
}
/* setup CERTIFY_INFO2 structure */
certifyInfo->tag = TPM_TAG_CERTIFY_INFO2;
certifyInfo->fill = 0x0000;
certifyInfo->keyUsage = key->keyUsage;
certifyInfo->keyFlags = key->keyFlags & TPM_KEY_FLAG_MASK;
certifyInfo->authDataUsage = key->authDataUsage;
certifyInfo->parentPCRStatus = key->parentPCRStatus;
if (tpm_setup_key_parms(key, &certifyInfo->algorithmParms)) return TPM_FAIL;
memcpy(&certifyInfo->data, antiReplay, sizeof(TPM_NONCE));
/* compute pubKeyDigest */
length = key->key.size >> 3;
buf = tpm_malloc(length);
if (buf == NULL) {
free_TPM_KEY_PARMS(certifyInfo->algorithmParms);
return TPM_FAIL;
}
tpm_rsa_export_modulus(&key->key, buf, NULL);
tpm_sha1_init(&sha1_ctx);
tpm_sha1_update(&sha1_ctx, buf, length);
tpm_sha1_final(&sha1_ctx, certifyInfo->pubkeyDigest.digest);
tpm_free(buf);
/* compute the digest of the CERTIFY_INFO[2] structure and sign it */
length = sizeof_TPM_CERTIFY_INFO((*certifyInfo));
p = buf = tpm_malloc(length);
if (buf == NULL
|| tpm_marshal_TPM_CERTIFY_INFO(&p, &length, certifyInfo)) {
free_TPM_KEY_PARMS(certifyInfo->algorithmParms);
return TPM_FAIL;
}
length = sizeof_TPM_CERTIFY_INFO((*certifyInfo));
tpm_sha1_init(&sha1_ctx);
tpm_sha1_update(&sha1_ctx, buf, length);
tpm_sha1_final(&sha1_ctx, buf);
res = tpm_sign(cert, auth1, FALSE, buf, SHA1_DIGEST_LENGTH, outData, outDataSize);
tpm_free(buf);
if (res != TPM_SUCCESS) {
free_TPM_KEY_PARMS(certifyInfo->algorithmParms);
return res;
}
return TPM_SUCCESS;
}