/*
* Licensed Materials - Property of IBM
*
* trousers - An open source TCG Software Stack
*
* (C) Copyright International Business Machines Corp. 2004-2006
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "trousers/tss.h"
#include "trousers/trousers.h"
#include "trousers_types.h"
#include "spi_utils.h"
#include "capabilities.h"
#include "tsplog.h"
#include "obj.h"
TSS_RESULT
Tspi_TPM_AuthorizeMigrationTicket(TSS_HTPM hTPM, /* in */
TSS_HKEY hMigrationKey, /* in */
TSS_MIGRATION_SCHEME migrationScheme, /* in */
UINT32 * pulMigTicketLength, /* out */
BYTE ** prgbMigTicket) /* out */
{
UINT64 offset;
TCPA_DIGEST digest;
TCPA_RESULT result;
TSS_HPOLICY hOwnerPolicy;
UINT32 migrationKeySize;
BYTE *migrationKeyBlob;
TSS_KEY tssKey;
BYTE pubKeyBlob[0x1000];
TPM_AUTH ownerAuth;
UINT32 pubKeySize;
TSS_HCONTEXT tspContext;
UINT32 tpmMigrationScheme;
Trspi_HashCtx hashCtx;
if (pulMigTicketLength == NULL || prgbMigTicket == NULL)
return TSPERR(TSS_E_BAD_PARAMETER);
if ((result = obj_tpm_get_tsp_context(hTPM, &tspContext)))
return result;
/* get the tpm Policy */
if ((result = obj_tpm_get_policy(hTPM, TSS_POLICY_USAGE, &hOwnerPolicy)))
return result;
switch (migrationScheme) {
case TSS_MS_MIGRATE:
tpmMigrationScheme = TCPA_MS_MIGRATE;
break;
case TSS_MS_REWRAP:
tpmMigrationScheme = TCPA_MS_REWRAP;
break;
case TSS_MS_MAINT:
tpmMigrationScheme = TCPA_MS_MAINT;
break;
#ifdef TSS_BUILD_CMK
case TSS_MS_RESTRICT_MIGRATE:
tpmMigrationScheme = TPM_MS_RESTRICT_MIGRATE;
break;
case TSS_MS_RESTRICT_APPROVE_DOUBLE:
tpmMigrationScheme = TPM_MS_RESTRICT_APPROVE_DOUBLE;
break;
#endif
default:
return TSPERR(TSS_E_BAD_PARAMETER);
break;
}
/* Get the migration key blob */
if ((result = obj_rsakey_get_blob(hMigrationKey, &migrationKeySize, &migrationKeyBlob)))
return result;
/* First, turn the keyBlob into a TSS_KEY structure */
offset = 0;
__tspi_memset(&tssKey, 0, sizeof(TSS_KEY));
if ((result = UnloadBlob_TSS_KEY(&offset, migrationKeyBlob, &tssKey))) {
free_tspi(tspContext, migrationKeyBlob);
return result;
}
free_tspi(tspContext, migrationKeyBlob);
/* Then pull the _PUBKEY portion out of that struct into a blob */
offset = 0;
Trspi_LoadBlob_KEY_PARMS(&offset, pubKeyBlob, &tssKey.algorithmParms);
Trspi_LoadBlob_STORE_PUBKEY(&offset, pubKeyBlob, &tssKey.pubKey);
pubKeySize = offset;
free_key_refs(&tssKey);
/* Auth */
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_AuthorizeMigrationKey);
result |= Trspi_Hash_UINT16(&hashCtx, tpmMigrationScheme);
result |= Trspi_HashUpdate(&hashCtx, pubKeySize, pubKeyBlob);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
return result;
if ((result = secret_PerformAuth_OIAP(hTPM, TPM_ORD_AuthorizeMigrationKey, hOwnerPolicy,
FALSE, &digest, &ownerAuth)))
return result;
/* Send command */
if ((result = TCS_API(tspContext)->AuthorizeMigrationKey(tspContext, migrationScheme,
pubKeySize, pubKeyBlob, &ownerAuth,
pulMigTicketLength,
prgbMigTicket)))
return result;
/* Validate Auth */
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, result);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_AuthorizeMigrationKey);
result |= Trspi_HashUpdate(&hashCtx, *pulMigTicketLength, *prgbMigTicket);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest))) {
*pulMigTicketLength = 0;
free(*prgbMigTicket);
return result;
}
if ((result = obj_policy_validate_auth_oiap(hOwnerPolicy, &digest, &ownerAuth))) {
*pulMigTicketLength = 0;
free(*prgbMigTicket);
return result;
}
if ((result = __tspi_add_mem_entry(tspContext, *prgbMigTicket))) {
*pulMigTicketLength = 0;
free(*prgbMigTicket);
return result;
}
return TSS_SUCCESS;
}
TSS_RESULT
Tspi_Key_CreateMigrationBlob(TSS_HKEY hKeyToMigrate, /* in */
TSS_HKEY hParentKey, /* in */
UINT32 ulMigTicketLength, /* in */
BYTE * rgbMigTicket, /* in */
UINT32 * pulRandomLength, /* out */
BYTE ** prgbRandom, /* out */
UINT32 * pulMigrationBlobLength, /* out */
BYTE ** prgbMigrationBlob) /* out */
{
TPM_AUTH parentAuth, entityAuth;
TPM_AUTH *pParentAuth;
TCPA_RESULT result;
UINT64 offset;
TCPA_DIGEST digest;
UINT32 keyToMigrateSize;
BYTE *keyToMigrateBlob = NULL;
TSS_HPOLICY hParentPolicy;
TSS_HPOLICY hMigratePolicy;
TCPA_MIGRATIONKEYAUTH migAuth;
TSS_KEY tssKey;
TCS_KEY_HANDLE parentHandle;
TSS_BOOL parentUsesAuth;
UINT32 randomSize;
BYTE *random = NULL;
UINT32 blobSize;
BYTE *blob = NULL;
TSS_HCONTEXT tspContext;
Trspi_HashCtx hashCtx;
__tspi_memset(&tssKey, 0, sizeof(TSS_KEY));
if (pulRandomLength == NULL || prgbRandom == NULL || rgbMigTicket == NULL ||
pulMigrationBlobLength == NULL || prgbMigrationBlob == NULL)
return TSPERR(TSS_E_BAD_PARAMETER);
if (!obj_is_rsakey(hKeyToMigrate))
return TSPERR(TSS_E_INVALID_HANDLE);
if ((result = obj_rsakey_get_tsp_context(hKeyToMigrate, &tspContext)))
return result;
if ((result = obj_rsakey_get_blob(hKeyToMigrate, &keyToMigrateSize, &keyToMigrateBlob)))
goto done;
if ((result = obj_rsakey_get_policy(hParentKey, TSS_POLICY_USAGE, &hParentPolicy,
&parentUsesAuth)))
goto done;
if ((result = obj_rsakey_get_policy(hKeyToMigrate, TSS_POLICY_MIGRATION, &hMigratePolicy,
NULL)))
goto done;
/* Parsing the migration scheme from the blob and key object */
__tspi_memset(&migAuth, 0, sizeof(TCPA_MIGRATIONKEYAUTH));
offset = 0;
if ((result = Trspi_UnloadBlob_MIGRATIONKEYAUTH(&offset, rgbMigTicket, &migAuth)))
goto done;
/* free these now, since none are used below */
free(migAuth.migrationKey.algorithmParms.parms);
migAuth.migrationKey.algorithmParms.parmSize = 0;
free(migAuth.migrationKey.pubKey.key);
migAuth.migrationKey.pubKey.keyLength = 0;
offset = 0;
if ((result = UnloadBlob_TSS_KEY(&offset, keyToMigrateBlob, &tssKey)))
goto done;
/* Generate the Authorization data */
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CreateMigrationBlob);
result |= Trspi_Hash_UINT16(&hashCtx, migAuth.migrationScheme);
result |= Trspi_HashUpdate(&hashCtx, ulMigTicketLength, rgbMigTicket);
result |= Trspi_Hash_UINT32(&hashCtx, tssKey.encSize);
result |= Trspi_HashUpdate(&hashCtx, tssKey.encSize, tssKey.encData);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
goto done;
if (parentUsesAuth) {
if ((result = secret_PerformAuth_OIAP(hParentPolicy, TPM_ORD_CreateMigrationBlob,
hParentPolicy, FALSE, &digest,
&parentAuth)))
goto done;
pParentAuth = &parentAuth;
} else {
pParentAuth = NULL;
}
if ((result = secret_PerformAuth_OIAP(hKeyToMigrate, TPM_ORD_CreateMigrationBlob,
hMigratePolicy, FALSE, &digest, &entityAuth)))
goto done;
if ((result = obj_rsakey_get_tcs_handle(hParentKey, &parentHandle)))
goto done;
if ((result = TCS_API(tspContext)->CreateMigrationBlob(tspContext, parentHandle,
migAuth.migrationScheme,
ulMigTicketLength, rgbMigTicket,
tssKey.encSize, tssKey.encData,
pParentAuth, &entityAuth,
&randomSize, &random,
&blobSize, &blob)))
goto done;
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, result);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_CreateMigrationBlob);
result |= Trspi_Hash_UINT32(&hashCtx, randomSize);
result |= Trspi_HashUpdate(&hashCtx, randomSize, random);
result |= Trspi_Hash_UINT32(&hashCtx, blobSize);
result |= Trspi_HashUpdate(&hashCtx, blobSize, blob);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
goto done;
if (parentUsesAuth) {
if ((result = obj_policy_validate_auth_oiap(hParentPolicy, &digest, &parentAuth)))
goto done;
}
if ((result = obj_policy_validate_auth_oiap(hMigratePolicy, &digest, &entityAuth)))
goto done;
free(tssKey.encData);
tssKey.encSize = blobSize;
tssKey.encData = blob;
/* Set blob to null since it will now be freed during key ref freeing */
blob = NULL;
offset = 0;
LoadBlob_TSS_KEY(&offset, NULL, &tssKey);
*pulMigrationBlobLength = offset;
*prgbMigrationBlob = calloc_tspi(tspContext, *pulMigrationBlobLength);
if (*prgbMigrationBlob == NULL) {
LogError("malloc of %u bytes failed.", *pulMigrationBlobLength);
result = TSPERR(TSS_E_OUTOFMEMORY);
goto done;
}
offset = 0;
LoadBlob_TSS_KEY(&offset, *prgbMigrationBlob, &tssKey);
if (randomSize) {
if ((result = __tspi_add_mem_entry(tspContext, random)))
goto done;
}
*pulRandomLength = randomSize;
*prgbRandom = random;
done:
if (result)
free(random);
free_tspi(tspContext, keyToMigrateBlob);
free_key_refs(&tssKey);
free(blob);
return result;
}
TSS_RESULT
Tspi_Key_ConvertMigrationBlob(TSS_HKEY hKeyToMigrate, /* in */
TSS_HKEY hParentKey, /* in */
UINT32 ulRandomLength, /* in */
BYTE * rgbRandom, /* in */
UINT32 ulMigrationBlobLength, /* in */
BYTE * rgbMigrationBlob) /* in */
{
TCPA_RESULT result;
TSS_KEY tssKey;
UINT32 outDataSize;
BYTE *outData = NULL;
TCS_KEY_HANDLE parentHandle;
TPM_AUTH parentAuth;
TSS_HPOLICY hParentPolicy;
TCPA_DIGEST digest;
TSS_BOOL useAuth;
TPM_AUTH *pParentAuth;
TSS_HCONTEXT tspContext;
Trspi_HashCtx hashCtx;
UINT64 offset;
__tspi_memset(&tssKey, 0, sizeof(TSS_KEY));
if ((result = obj_rsakey_get_tsp_context(hKeyToMigrate, &tspContext)))
return result;
if (!obj_is_rsakey(hParentKey))
return TSPERR(TSS_E_INVALID_HANDLE);
/* Get the parent key handle */
if ((result = obj_rsakey_get_tcs_handle(hParentKey, &parentHandle)))
return result;
/* Get the policy */
if ((result = obj_rsakey_get_policy(hParentKey, TSS_POLICY_USAGE,
&hParentPolicy, &useAuth)))
return result;
offset = 0;
if ((result = UnloadBlob_TSS_KEY(&offset, rgbMigrationBlob, &tssKey)))
return result;
/* Generate the authorization */
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ConvertMigrationBlob);
result |= Trspi_Hash_UINT32(&hashCtx, tssKey.encSize);
result |= Trspi_HashUpdate(&hashCtx, tssKey.encSize, tssKey.encData);
result |= Trspi_Hash_UINT32(&hashCtx, ulRandomLength);
result |= Trspi_HashUpdate(&hashCtx, ulRandomLength, rgbRandom);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
goto done;
if (useAuth) {
if ((result = secret_PerformAuth_OIAP(hParentPolicy, TPM_ORD_ConvertMigrationBlob,
hParentPolicy, FALSE, &digest, &parentAuth)))
goto done;
pParentAuth = &parentAuth;
} else {
pParentAuth = NULL;
}
if ((result = TCS_API(tspContext)->ConvertMigrationBlob(tspContext, parentHandle,
tssKey.encSize, tssKey.encData,
ulRandomLength, rgbRandom,
pParentAuth,
&outDataSize, &outData)))
goto done;
/* add validation */
result = Trspi_HashInit(&hashCtx, TSS_HASH_SHA1);
result |= Trspi_Hash_UINT32(&hashCtx, result);
result |= Trspi_Hash_UINT32(&hashCtx, TPM_ORD_ConvertMigrationBlob);
result |= Trspi_Hash_UINT32(&hashCtx, outDataSize);
result |= Trspi_HashUpdate(&hashCtx, outDataSize, outData);
if ((result |= Trspi_HashFinal(&hashCtx, digest.digest)))
goto done;
if (useAuth) {
if ((result = obj_policy_validate_auth_oiap(hParentPolicy, &digest, &parentAuth)))
goto done;
}
/* Set the key object to the now migrated key */
if ((result = obj_rsakey_set_tcpakey(hKeyToMigrate, ulMigrationBlobLength, rgbMigrationBlob)))
goto done;
if ((result = obj_rsakey_set_privkey(hKeyToMigrate, TRUE, outDataSize, outData)))
goto done;
result = obj_rsakey_set_tcs_handle(hKeyToMigrate, 0);
done:
free_key_refs(&tssKey);
free(outData);
return result;
}