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