blob: f40f58ae25823598e95eef4a5923788dfb23ebbf [file] [log] [blame]
/* Software-based Trusted Platform Module (TPM) Emulator
* Copyright (C) 2004-2010 Mario Strasser <mast@gmx.net>
* 2005-2008 Heiko Stamer <stamer@gaos.org>
*
* 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_capability.c 407 2010-02-19 11:14:52Z mast $
*/
#include "tpm_emulator.h"
#include "tpm_commands.h"
#include "tpm_marshalling.h"
#include "tpm_data.h"
#include "tpm_handles.h"
/*
* The GetCapability Commands ([TPM_Part3], Section 7)
* The GetCapability command allows the TPM to report back to the requester
* what type of TPM it is dealing with. The request for information requires
* the requester to specify which piece of information that is required.
*/
static inline TPM_RESULT return_UINT32(UINT32 *respSize, BYTE **resp, UINT32 value)
{
UINT32 len = *respSize = 4;
BYTE *ptr = *resp = tpm_malloc(*respSize);
if (ptr == NULL || tpm_marshal_UINT32(&ptr, &len, value)) {
tpm_free(*resp);
return TPM_FAIL;
}
return TPM_SUCCESS;
}
static inline TPM_RESULT return_UINT32_array(UINT32 *respSize, BYTE **resp,
UINT32 *array, UINT32 array_len)
{
UINT32 len = *respSize = 4 * array_len;
BYTE *ptr = *resp = tpm_malloc(*respSize);
if (ptr == NULL || tpm_marshal_UINT32_ARRAY(&ptr, &len, array, array_len)) {
tpm_free(*resp);
return TPM_FAIL;
}
return TPM_SUCCESS;
}
static inline TPM_RESULT return_BOOL(UINT32 *respSize, BYTE **resp, BOOL value)
{
UINT32 len = *respSize = 1;
BYTE *ptr = *resp = tpm_malloc(*respSize);
if (ptr == NULL || tpm_marshal_BOOL(&ptr, &len, value)) {
tpm_free(*resp);
return TPM_FAIL;
}
return TPM_SUCCESS;
}
static TPM_RESULT cap_property(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
UINT32 i, j, property;
if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &property))
return TPM_BAD_MODE;
switch (property) {
case TPM_CAP_PROP_PCR:
debug("[TPM_CAP_PROP_PCR]");
return return_UINT32(respSize, resp, TPM_NUM_PCR);
case TPM_CAP_PROP_DIR:
debug("[TPM_CAP_PROP_DIR]");
return return_UINT32(respSize, resp, 1);
case TPM_CAP_PROP_MANUFACTURER:
debug("[TPM_CAP_PROP_MANUFACTURER]");
return return_UINT32(respSize, resp, TPM_MANUFACTURER);
case TPM_CAP_PROP_KEYS:
debug("[TPM_CAP_PROP_KEYS]");
for (i = 0, j = TPM_MAX_KEYS; i < TPM_MAX_KEYS; i++)
if (tpmData.permanent.data.keys[i].payload) j--;
return return_UINT32(respSize, resp, j);
case TPM_CAP_PROP_MIN_COUNTER:
debug("[TPM_CAP_PROP_MIN_COUNTER]");
return return_UINT32(respSize, resp, 1);
case TPM_CAP_PROP_AUTHSESS:
debug("[TPM_CAP_PROP_AUTHSESS]");
for (i = 0, j = TPM_MAX_SESSIONS; i < TPM_MAX_SESSIONS; i++)
if (tpmData.stany.data.sessions[i].type != TPM_ST_INVALID) j--;
return return_UINT32(respSize, resp, j);
case TPM_CAP_PROP_TRANSESS:
debug("[TPM_CAP_PROP_TRANSESS]");
for (i = 0, j = TPM_MAX_SESSIONS; i < TPM_MAX_SESSIONS; i++)
if (tpmData.stany.data.sessions[i].type != TPM_ST_INVALID) j--;
return return_UINT32(respSize, resp, j);
case TPM_CAP_PROP_COUNTERS:
debug("[TPM_CAP_PROP_COUNTERS]");
for (i = 0, j = TPM_MAX_COUNTERS; i < TPM_MAX_COUNTERS; i++)
if (tpmData.permanent.data.counters[i].valid) j--;
return return_UINT32(respSize, resp, j);
case TPM_CAP_PROP_MAX_AUTHSESS:
debug("[TPM_CAP_PROP_MAX_AUTHSESS]");
return return_UINT32(respSize, resp, TPM_MAX_SESSIONS);
case TPM_CAP_PROP_MAX_TRANSESS:
debug("[TPM_CAP_PROP_MAX_TRANSESS]");
return return_UINT32(respSize, resp, TPM_MAX_SESSIONS);
case TPM_CAP_PROP_MAX_COUNTERS:
debug("[TPM_CAP_PROP_MAX_COUNTERS]");
return return_UINT32(respSize, resp, TPM_MAX_COUNTERS);
case TPM_CAP_PROP_MAX_KEYS:
debug("[TPM_CAP_PROP_MAX_KEYS]");
return return_UINT32(respSize, resp, TPM_MAX_KEYS);
case TPM_CAP_PROP_OWNER:
debug("[TPM_CAP_PROP_OWNER]");
return return_BOOL(respSize, resp, tpmData.permanent.flags.owned);
case TPM_CAP_PROP_CONTEXT:
debug("[TPM_CAP_PROP_CONTEXT]");
for (i = 0, j = 0; i < TPM_MAX_SESSION_LIST; i++)
if (tpmData.stany.data.contextList[i] == 0) j++;
return return_UINT32(respSize, resp, j);
case TPM_CAP_PROP_MAX_CONTEXT:
debug("[TPM_CAP_PROP_MAX_CONTEXT]");
return return_UINT32(respSize, resp, TPM_MAX_SESSION_LIST);
case TPM_CAP_PROP_FAMILYROWS:
debug("[TPM_CAP_PROP_FAMILYROWS]");
return return_UINT32(respSize, resp, TPM_NUM_FAMILY_TABLE_ENTRY);
case TPM_CAP_PROP_TIS_TIMEOUT:
debug("[TPM_CAP_PROP_TIS_TIMEOUT]");
return return_UINT32_array(respSize, resp,
tpmData.permanent.data.tis_timeouts, TPM_NUM_TIS_TIMEOUTS);
case TPM_CAP_PROP_STARTUP_EFFECT:
debug("[TPM_CAP_PROP_STARTUP_EFFECT]");
return return_UINT32(respSize, resp, 0x4f);
case TPM_CAP_PROP_DELEGATE_ROW:
debug("[TPM_CAP_PROP_DELEGATE_ROW]");
return return_UINT32(respSize, resp, TPM_NUM_DELEGATE_TABLE_ENTRY);
case TPM_CAP_PROP_MAX_DAASESS:
debug("[TPM_CAP_PROP_MAX_DAASESS]");
return return_UINT32(respSize, resp, TPM_MAX_SESSIONS_DAA);
case TPM_CAP_PROP_DAASESS:
debug("[TPM_CAP_PROP_DAASESS]");
for (i = 0, j = TPM_MAX_SESSIONS_DAA; i < TPM_MAX_SESSIONS_DAA; i++)
if (tpmData.stany.data.sessionsDAA[i].type != TPM_ST_INVALID) j--;
return return_UINT32(respSize, resp, j);
case TPM_CAP_PROP_CONTEXT_DIST:
debug("[TPM_CAP_PROP_CONTEXT_DIST]");
return return_UINT32(respSize, resp, 0xfffffffe);
case TPM_CAP_PROP_DAA_INTERRUPT:
debug("[TPM_CAP_PROP_DAA_INTERRUPT]");
/* A value of TRUE indicates that the TPM will accept ANY command
* while executing a DAA Join or Sign. A value of FALSE indicates
* that the TPM will invalidate the DAA Join or Sign upon the
* receipt of any command other than the next join/sign in the
* session or a TPM_SaveContext. */
return return_BOOL(respSize, resp, TRUE);
case TPM_CAP_PROP_SESSIONS:
debug("[TPM_CAP_PROP_SESSIONS]");
for (i = 0, j = TPM_MAX_SESSIONS; i < TPM_MAX_SESSIONS; i++)
if (tpmData.stany.data.sessions[i].type != TPM_ST_INVALID) j--;
return return_UINT32(respSize, resp, j);
case TPM_CAP_PROP_MAX_SESSIONS:
debug("[TPM_CAP_PROP_MAX_SESSIONS]");
return return_UINT32(respSize, resp, TPM_MAX_SESSIONS);
case TPM_CAP_PROP_CMK_RESTRICTION:
debug("[TPM_CAP_PROP_CMK_RESTRICTION]");
return return_UINT32(respSize, resp,
tpmData.permanent.data.restrictDelegate);
case TPM_CAP_PROP_DURATION:
debug("[TPM_CAP_PROP_DURATION]");
return return_UINT32_array(respSize, resp,
tpmData.permanent.data.cmd_durations, TPM_NUM_CMD_DURATIONS);
case TPM_CAP_PROP_ACTIVE_COUNTER:
debug("[TPM_CAP_PROP_ACTIVE_COUNTER]");
return return_UINT32(respSize, resp, tpmData.stclear.data.countID);
case TPM_CAP_PROP_MAX_NV_AVAILABLE:
debug("[TPM_CAP_PROP_MAX_NV_AVAILABLE]");
return return_UINT32(respSize, resp, TPM_MAX_NV_SIZE
- tpmData.permanent.data.nvDataSize);
case TPM_CAP_PROP_INPUT_BUFFER:
debug("[TPM_CAP_PROP_INPUT_BUFFER]");
return return_UINT32(respSize, resp, TPM_CMD_BUF_SIZE);
default:
return TPM_BAD_MODE;
}
}
/* changed since v1.2 rev 94: returned version MUST BE 1.1.0.0 */
static TPM_RESULT cap_version(UINT32 *respSize, BYTE **resp)
{
UINT32 len = *respSize = 4;
BYTE *ptr = *resp = tpm_malloc(*respSize);
TPM_STRUCT_VER version;
version.major = version.minor = 1;
version.revMajor = version.revMinor = 0;
if (ptr == NULL || tpm_marshal_TPM_STRUCT_VER(&ptr, &len, &version)) {
tpm_free(*resp);
return TPM_FAIL;
}
return TPM_SUCCESS;
}
/* manufacturer specific */
static TPM_RESULT cap_mfr(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
UINT32 len = *respSize = 4, type;
BYTE *ptr = *resp = tpm_malloc(*respSize);
if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &type))
return TPM_BAD_MODE;
switch (type) {
default:
if (ptr == NULL || tpm_marshal_TPM_VERSION(&ptr, &len,
&tpmData.permanent.data.version)) {
tpm_free(*resp);
return TPM_FAIL;
}
return TPM_SUCCESS;
}
}
static TPM_RESULT cap_nv_list(UINT32 *respSize, BYTE **resp)
{
UINT32 i, len;
BYTE *ptr = *resp = tpm_malloc(TPM_MAX_NVS * sizeof(TPM_NV_INDEX));
if (ptr == NULL) return TPM_FAIL;
*respSize = 0;
for (i = 0; i < TPM_MAX_NVS; i++) {
if (tpmData.permanent.data.nvStorage[i].valid) {
len = sizeof(TPM_NV_INDEX);
ptr = (*resp) + *respSize;
*respSize += len;
if (tpm_marshal_UINT32(&ptr, &len,
tpmData.permanent.data.nvStorage[i].pubInfo.nvIndex)) {
tpm_free(*resp);
return TPM_FAIL;
}
}
}
return TPM_SUCCESS;
}
static TPM_RESULT cap_nv_index(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
TPM_NV_INDEX nvIndex;
TPM_NV_DATA_SENSITIVE *nv;
UINT32 len;
BYTE *ptr;
if (tpm_unmarshal_TPM_NV_INDEX(&subCap, &subCapSize, &nvIndex))
return TPM_BAD_MODE;
nv = tpm_get_nvs(nvIndex);
if (nv == NULL) return TPM_BADINDEX;
len = *respSize = sizeof_TPM_NV_DATA_PUBLIC(nv->pubInfo);
ptr = *resp = tpm_malloc(len);
if (ptr == NULL
|| tpm_marshal_TPM_NV_DATA_PUBLIC(&ptr, &len, &nv->pubInfo)) {
tpm_free(*resp);
return TPM_FAIL;
}
*respSize -= len;
return TPM_SUCCESS;
}
static TPM_RESULT cap_handle(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
UINT32 i, len, type;
BYTE *ptr;
/* maximum of { TPM_MAX_KEYS, TPM_MAX_SESSIONS } */
UINT32 list_size =
(TPM_MAX_KEYS > TPM_MAX_SESSIONS) ? TPM_MAX_KEYS : TPM_MAX_SESSIONS;
UINT32 handles[list_size];
TPM_KEY_HANDLE_LIST list = { 0, handles };
if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &type))
return TPM_BAD_MODE;
switch (type) {
case TPM_RT_KEY:
debug("[TPM_RT_KEY]");
for (i = 0; i < TPM_MAX_KEYS; i++)
if (tpmData.permanent.data.keys[i].payload) {
list.loaded++;
list.handle[i] = INDEX_TO_KEY_HANDLE(i);
}
break;
case TPM_RT_AUTH:
debug("[TPM_RT_AUTH]");
for (i = 0; i < TPM_MAX_SESSIONS; i++)
if (tpmData.stany.data.sessions[i].type == TPM_ST_OIAP
|| tpmData.stany.data.sessions[i].type == TPM_ST_OSAP) {
list.loaded++;
list.handle[i] = INDEX_TO_AUTH_HANDLE(i);
}
break;
case TPM_RT_TRANS:
debug("[TPM_RT_TRANS]");
for (i = 0; i < TPM_MAX_SESSIONS; i++)
if (tpmData.stany.data.sessions[i].type == TPM_ST_TRANSPORT) {
list.loaded++;
list.handle[i] = INDEX_TO_TRANS_HANDLE(i);
}
break;
case TPM_RT_COUNTER:
debug("[TPM_RT_COUNTER]");
for (i = 0; i < TPM_MAX_COUNTERS; i++)
if (tpmData.permanent.data.counters[i].valid) {
list.loaded++;
list.handle[i] = INDEX_TO_COUNTER_HANDLE(i);
}
break;
case TPM_RT_CONTEXT:
debug("[TPM_RT_CONTEXT]");
for (i = 0; i < TPM_MAX_SESSION_LIST; i++)
if (tpmData.stany.data.contextList[i] != 0) {
list.loaded++;
list.handle[i] = tpmData.stany.data.contextList[i];
}
break;
default:
return TPM_BAD_MODE;
}
/* marshal handle list */
len = *respSize = 2 + list.loaded * 4;
ptr = *resp = tpm_malloc(len);
if (ptr == NULL || tpm_marshal_TPM_KEY_HANDLE_LIST(&ptr, &len, &list)) {
tpm_free(*resp);
return TPM_FAIL;
}
return TPM_SUCCESS;
}
static TPM_RESULT cap_ord(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
TPM_COMMAND_CODE ord;
if (tpm_unmarshal_TPM_COMMAND_CODE(&subCap, &subCapSize, &ord))
return TPM_BAD_MODE;
switch (ord) {
case TPM_ORD_Init:
case TPM_ORD_Startup:
case TPM_ORD_SaveState:
case TPM_ORD_SelfTestFull:
case TPM_ORD_ContinueSelfTest:
case TPM_ORD_GetTestResult:
case TPM_ORD_SetOwnerInstall:
case TPM_ORD_OwnerSetDisable:
case TPM_ORD_PhysicalEnable:
case TPM_ORD_PhysicalDisable:
case TPM_ORD_PhysicalSetDeactivated:
case TPM_ORD_SetTempDeactivated:
case TPM_ORD_SetOperatorAuth:
case TPM_ORD_TakeOwnership:
case TPM_ORD_OwnerClear:
case TPM_ORD_ForceClear:
case TPM_ORD_DisableOwnerClear:
case TPM_ORD_DisableForceClear:
case TSC_ORD_PhysicalPresence:
case TSC_ORD_ResetEstablishmentBit:
case TPM_ORD_GetCapability:
case TPM_ORD_SetCapability:
case TPM_ORD_GetCapabilityOwner:
case TPM_ORD_GetAuditDigest:
case TPM_ORD_GetAuditDigestSigned:
case TPM_ORD_SetOrdinalAuditStatus:
case TPM_ORD_FieldUpgrade:
case TPM_ORD_SetRedirection:
case TPM_ORD_ResetLockValue:
case TPM_ORD_Seal:
case TPM_ORD_Unseal:
case TPM_ORD_UnBind:
case TPM_ORD_CreateWrapKey:
case TPM_ORD_LoadKey2:
case TPM_ORD_GetPubKey:
case TPM_ORD_Sealx:
case TPM_ORD_CreateMigrationBlob:
case TPM_ORD_ConvertMigrationBlob:
case TPM_ORD_AuthorizeMigrationKey:
case TPM_ORD_MigrateKey:
case TPM_ORD_CMK_SetRestrictions:
case TPM_ORD_CMK_ApproveMA:
case TPM_ORD_CMK_CreateKey:
case TPM_ORD_CMK_CreateTicket:
case TPM_ORD_CMK_CreateBlob:
case TPM_ORD_CMK_ConvertMigration:
case TPM_ORD_CreateMaintenanceArchive:
case TPM_ORD_LoadMaintenanceArchive:
case TPM_ORD_KillMaintenanceFeature:
case TPM_ORD_LoadManuMaintPub:
case TPM_ORD_ReadManuMaintPub:
case TPM_ORD_SHA1Start:
case TPM_ORD_SHA1Update:
case TPM_ORD_SHA1Complete:
case TPM_ORD_SHA1CompleteExtend:
case TPM_ORD_Sign:
case TPM_ORD_GetRandom:
case TPM_ORD_StirRandom:
case TPM_ORD_CertifyKey:
case TPM_ORD_CertifyKey2:
case TPM_ORD_CreateEndorsementKeyPair:
case TPM_ORD_CreateRevocableEK:
case TPM_ORD_RevokeTrust:
case TPM_ORD_ReadPubek:
case TPM_ORD_OwnerReadInternalPub:
case TPM_ORD_MakeIdentity:
case TPM_ORD_ActivateIdentity:
case TPM_ORD_Extend:
case TPM_ORD_PCRRead:
case TPM_ORD_Quote:
case TPM_ORD_PCR_Reset:
case TPM_ORD_Quote2:
case TPM_ORD_ChangeAuth:
case TPM_ORD_ChangeAuthOwner:
case TPM_ORD_OIAP:
case TPM_ORD_OSAP:
case TPM_ORD_DSAP:
case TPM_ORD_SetOwnerPointer:
case TPM_ORD_Delegate_Manage:
case TPM_ORD_Delegate_CreateKeyDelegation:
case TPM_ORD_Delegate_CreateOwnerDelegation:
case TPM_ORD_Delegate_LoadOwnerDelegation:
case TPM_ORD_Delegate_ReadTable:
case TPM_ORD_Delegate_UpdateVerification:
case TPM_ORD_Delegate_VerifyDelegation:
case TPM_ORD_NV_DefineSpace:
case TPM_ORD_NV_WriteValue:
case TPM_ORD_NV_WriteValueAuth:
case TPM_ORD_NV_ReadValue:
case TPM_ORD_NV_ReadValueAuth:
case TPM_ORD_KeyControlOwner:
case TPM_ORD_SaveContext:
case TPM_ORD_LoadContext:
case TPM_ORD_FlushSpecific:
case TPM_ORD_GetTicks:
case TPM_ORD_TickStampBlob:
case TPM_ORD_EstablishTransport:
case TPM_ORD_ExecuteTransport:
case TPM_ORD_ReleaseTransportSigned:
case TPM_ORD_CreateCounter:
case TPM_ORD_IncrementCounter:
case TPM_ORD_ReadCounter:
case TPM_ORD_ReleaseCounter:
case TPM_ORD_ReleaseCounterOwner:
case TPM_ORD_DAA_Join:
case TPM_ORD_DAA_Sign:
/* Deprecated but supported are the following commands */
case TPM_ORD_EvictKey:
case TPM_ORD_Terminate_Handle:
case TPM_ORD_SaveKeyContext:
case TPM_ORD_LoadKeyContext:
case TPM_ORD_SaveAuthContext:
case TPM_ORD_LoadAuthContext:
case TPM_ORD_DirWriteAuth:
case TPM_ORD_DirRead:
case TPM_ORD_ChangeAuthAsymStart:
case TPM_ORD_ChangeAuthAsymFinish:
case TPM_ORD_Reset:
case TPM_ORD_OwnerReadPubek:
case TPM_ORD_DisablePubekRead:
case TPM_ORD_LoadKey:
return return_BOOL(respSize, resp, TRUE);
default:
return return_BOOL(respSize, resp, FALSE);
}
}
static TPM_RESULT cap_alg(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
TPM_ALGORITHM_ID id;
if (tpm_unmarshal_TPM_ALGORITHM_ID(&subCap, &subCapSize, &id))
return TPM_BAD_MODE;
switch (id) {
case TPM_ALG_RSA:
return return_BOOL(respSize, resp, TRUE);
default:
return return_BOOL(respSize, resp, FALSE);
}
}
static TPM_RESULT cap_pid(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
TPM_PROTOCOL_ID id;
if (tpm_unmarshal_TPM_PROTOCOL_ID(&subCap, &subCapSize, &id))
return TPM_BAD_MODE;
switch (id) {
case TPM_PID_OIAP:
case TPM_PID_OSAP:
case TPM_PID_ADIP:
case TPM_PID_ADCP:
case TPM_PID_OWNER:
case TPM_PID_DSAP:
case TPM_PID_TRANSPORT:
return return_BOOL(respSize, resp, TRUE);
default:
return return_BOOL(respSize, resp, FALSE);
}
}
static TPM_RESULT cap_flag(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
UINT32 type, len;
BYTE *ptr;
if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &type)) return TPM_BAD_MODE;
switch (type) {
case TPM_CAP_FLAG_PERMANENT:
debug("[TPM_CAP_FLAG_PERMANENT");
*respSize = len = sizeof_TPM_PERMANENT_FLAGS(tpmData.permanent.flags);
*resp = ptr = tpm_malloc(len);
if (tpm_marshal_TPM_PERMANENT_FLAGS(&ptr, &len, &tpmData.permanent.flags)) {
tpm_free(*resp);
return TPM_FAIL;
}
return TPM_SUCCESS;
case TPM_CAP_FLAG_VOLATILE:
debug("[TPM_CAP_FLAG_VOLATILE]");
*respSize = len = sizeof_TPM_STCLEAR_FLAGS(tpmData.stclear.flags);
*resp = ptr = tpm_malloc(len);
if (tpm_marshal_TPM_STCLEAR_FLAGS(&ptr, &len, &tpmData.stclear.flags)) {
tpm_free(*resp);
return TPM_FAIL;
}
return TPM_SUCCESS;
default:
return TPM_BAD_MODE;
}
}
static TPM_RESULT cap_loaded(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
int i;
BOOL free_space = FALSE;
TPM_KEY_PARMS parms;
if (tpm_unmarshal_TPM_KEY_PARMS(&subCap, &subCapSize, &parms))
return TPM_BAD_MODE;
for (i = 0; i < TPM_MAX_KEYS; i++)
if (!tpmData.permanent.data.keys[i].payload) free_space = TRUE;
if (free_space
&& parms.algorithmID == TPM_ALG_RSA
&& parms.parms.rsa.keyLength <= 2048
&& parms.parms.rsa.numPrimes == 2)
return return_BOOL(respSize, resp, TRUE);
return return_BOOL(respSize, resp, FALSE);
}
static TPM_RESULT cap_auth_encrypt(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
TPM_ALGORITHM_ID id;
if (tpm_unmarshal_TPM_ALGORITHM_ID(&subCap, &subCapSize, &id))
return TPM_BAD_MODE;
switch (id) {
case TPM_ALG_XOR:
return return_BOOL(respSize, resp, TRUE);
default:
return return_BOOL(respSize, resp, FALSE);
}
}
static TPM_RESULT cap_sym_mode(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
TPM_SYM_MODE mode;
if (tpm_unmarshal_TPM_SYM_MODE(&subCap, &subCapSize, &mode))
return TPM_BAD_MODE;
switch (mode) {
case TPM_ES_SYM_CTR:
case TPM_ES_SYM_OFB:
default:
return return_BOOL(respSize, resp, FALSE);
}
}
static TPM_RESULT cap_key_status(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
TPM_KEY_HANDLE handle;
TPM_KEY_DATA *key;
if (tpm_unmarshal_TPM_KEY_HANDLE(&subCap, &subCapSize, &handle))
return TPM_BAD_MODE;
key = tpm_get_key(handle);
if (key == NULL) return TPM_INVALID_KEYHANDLE;
return return_BOOL(respSize, resp,
key->keyControl & TPM_KEY_CONTROL_OWNER_EVICT);
}
static TPM_RESULT cap_trans_alg(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
TPM_ALGORITHM_ID id;
if (tpm_unmarshal_TPM_ALGORITHM_ID(&subCap, &subCapSize, &id))
return TPM_BAD_MODE;
switch (id) {
case TPM_ALG_RSA:
return return_BOOL(respSize, resp, TRUE);
default:
return return_BOOL(respSize, resp, FALSE);
}
}
static TPM_RESULT cap_trans_es(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
TPM_ENC_SCHEME es;
if (tpm_unmarshal_TPM_ENC_SCHEME(&subCap, &subCapSize, &es))
return TPM_BAD_MODE;
switch (es) {
case TPM_ES_RSAESOAEP_SHA1_MGF1:
case TPM_ES_RSAESPKCSv15:
return return_BOOL(respSize, resp, TRUE);
default:
return return_BOOL(respSize, resp, FALSE);
}
}
static TPM_RESULT cap_select_size(UINT32 subCapSize, BYTE *subCap,
UINT32 *respSize, BYTE **resp)
{
TPM_SELECT_SIZE size;
if (tpm_unmarshal_TPM_SELECT_SIZE(&subCap, &subCapSize, &size))
return TPM_BAD_MODE;
return return_BOOL(respSize, resp, (size.reqSize <= TPM_NUM_PCR/8));
}
static TPM_RESULT cap_version_val(UINT32 *respSize, BYTE **resp)
{
UINT32 len;
BYTE *ptr;
TPM_CAP_VERSION_INFO version;
version.tag = TPM_TAG_CAP_VERSION_INFO;
version.version = tpmData.permanent.data.version;
version.specLevel = 0x0002; /* see [TPM_Part2], Section 21.6 */
version.errataRev = 0x01; /* 0x01 = rev 94, 0x02 = rev 103 */
len = 4, ptr = version.tpmVendorID;
if (tpm_marshal_UINT32(&ptr, &len, TPM_MANUFACTURER))
return TPM_FAIL;
version.vendorSpecificSize = 0;
version.vendorSpecific = NULL;
len = *respSize = sizeof_TPM_CAP_VERSION_INFO(version);
ptr = *resp = tpm_malloc(*respSize);
if (ptr == NULL || tpm_marshal_TPM_CAP_VERSION_INFO(&ptr, &len, &version)) {
tpm_free(*resp);
return TPM_FAIL;
}
return TPM_SUCCESS;
}
TPM_RESULT TPM_GetCapability(TPM_CAPABILITY_AREA capArea, UINT32 subCapSize,
BYTE *subCap, UINT32 *respSize, BYTE **resp)
{
info("TPM_GetCapability()");
switch (capArea) {
case TPM_CAP_ORD:
debug("[TPM_CAP_ORD]");
return cap_ord(subCapSize, subCap, respSize, resp);
case TPM_CAP_ALG:
debug("[TPM_CAP_ALG]");
return cap_alg(subCapSize, subCap, respSize, resp);
case TPM_CAP_PID:
debug("[TPM_CAP_PID]");
return cap_pid(subCapSize, subCap, respSize, resp);
case TPM_CAP_FLAG:
debug("[TPM_CAP_FLAG]");
return cap_flag(subCapSize, subCap, respSize, resp);
case TPM_CAP_PROPERTY:
debug("[TPM_CAP_PROPERTY]");
return cap_property(subCapSize, subCap, respSize, resp);
case TPM_CAP_VERSION:
debug("[TPM_CAP_VERSION]");
return cap_version(respSize, resp);
case TPM_CAP_KEY_HANDLE:
debug("[TPM_CAP_KEY_HANDLE]");
BYTE buf[4];
buf[0] = (TPM_RT_KEY >> 24) & 0xff;
buf[1] = (TPM_RT_KEY >> 16) & 0xff;
buf[2] = (TPM_RT_KEY >> 8) & 0xff;
buf[3] = TPM_RT_KEY & 0xff;
return cap_handle(4, buf, respSize, resp);
case TPM_CAP_CHECK_LOADED:
debug("[TPM_CAP_CHECK_LOADED]");
return cap_loaded(subCapSize, subCap, respSize, resp);
case TPM_CAP_SYM_MODE:
debug("[TPM_CAP_SYM_MODE]");
return cap_sym_mode(subCapSize, subCap, respSize, resp);
case TPM_CAP_KEY_STATUS:
debug("[TPM_CAP_KEY_STATUS]");
return cap_key_status(subCapSize, subCap, respSize, resp);
case TPM_CAP_NV_LIST:
debug("[TPM_CAP_NV_LIST]");
return cap_nv_list(respSize, resp);
case TPM_CAP_MFR:
debug("[TPM_CAP_MFR]");
return cap_mfr(subCapSize, subCap, respSize, resp);
case TPM_CAP_NV_INDEX:
debug("[TPM_CAP_NV_INDEX]");
return cap_nv_index(subCapSize, subCap, respSize, resp);
case TPM_CAP_TRANS_ALG:
debug("[TPM_CAP_TRANS_ALG]");
return cap_trans_alg(subCapSize, subCap, respSize, resp);
case TPM_CAP_HANDLE:
debug("[TPM_CAP_HANDLE]");
return cap_handle(subCapSize, subCap, respSize, resp);
case TPM_CAP_TRANS_ES:
debug("[TPM_CAP_TRANS_ES]");
return cap_trans_es(subCapSize, subCap, respSize, resp);
case TPM_CAP_AUTH_ENCRYPT:
debug("[TPM_CAP_AUTH_ENCRYPT]");
return cap_auth_encrypt(subCapSize, subCap, respSize, resp);
case TPM_CAP_SELECT_SIZE:
debug("[TPM_CAP_SELECT_SIZE]");
return cap_select_size(subCapSize, subCap, respSize, resp);
case TPM_CAP_VERSION_VAL:
debug("[TPM_CAP_VERSION_VAL]");
return cap_version_val(respSize, resp);
default:
return TPM_BAD_MODE;
}
}
static TPM_RESULT set_perm_flags(UINT32 subCap, BOOL flag, BOOL ownerAuth,
BOOL deactivated, BOOL disabled)
{
switch (subCap) {
case 1:
if (!ownerAuth && !tpm_get_physical_presence()) return TPM_AUTHFAIL;
tpmData.permanent.flags.disable = flag;
return TPM_SUCCESS;
case 2:
if (!tpm_get_physical_presence()) return TPM_AUTHFAIL;
if (tpmData.permanent.flags.owned) return TPM_OWNER_SET;
if (deactivated) return TPM_DEACTIVATED;
if (disabled) return TPM_DISABLED;
tpmData.permanent.flags.ownership = flag;
return TPM_SUCCESS;
case 3:
if (!tpm_get_physical_presence()) return TPM_AUTHFAIL;
if (disabled) return TPM_DISABLED;
tpmData.permanent.flags.deactivated = flag;
return TPM_SUCCESS;
case 4:
if (!ownerAuth) return TPM_AUTHFAIL;
if (deactivated) return TPM_DEACTIVATED;
if (disabled) return TPM_DISABLED;
tpmData.permanent.flags.readPubek = flag;
return TPM_SUCCESS;
case 5:
if (!ownerAuth) return TPM_AUTHFAIL;
if (deactivated) return TPM_DEACTIVATED;
if (disabled) return TPM_DISABLED;
if (flag == FALSE) return TPM_BAD_PARAMETER;
tpmData.permanent.flags.disableOwnerClear = TRUE;
return TPM_SUCCESS;
case 6:
if (!ownerAuth) return TPM_AUTHFAIL;
if (deactivated) return TPM_DEACTIVATED;
if (disabled) return TPM_DISABLED;
if (flag == TRUE) return TPM_BAD_PARAMETER;
tpmData.permanent.flags.allowMaintenance = FALSE;
return TPM_SUCCESS;
case 17:
if (!ownerAuth) return TPM_AUTHFAIL;
if (deactivated) return TPM_DEACTIVATED;
if (disabled) return TPM_DISABLED;
tpmData.permanent.flags.readSRKPub = flag;
return TPM_SUCCESS;
case 18:
if (tpmData.stany.flags.localityModifier
& (TPM_LOC_THREE | TPM_LOC_FOUR)) return TPM_BAD_LOCALITY;
if (flag == TRUE) return TPM_BAD_PARAMETER;
tpmData.permanent.flags.tpmEstablished = FALSE;
return TPM_SUCCESS;
case 20:
if (!ownerAuth) return TPM_AUTHFAIL;
tpmData.permanent.flags.disableFullDALogicInfo = flag;
return TPM_SUCCESS;
}
return TPM_BAD_PARAMETER;
}
static TPM_RESULT set_stclear_flags(UINT32 subCap, BOOL flag, BOOL ownerAuth,
BOOL deactivated, BOOL disabled)
{
switch (subCap) {
case 2:
if (deactivated) return TPM_DEACTIVATED;
if (disabled) return TPM_DISABLED;
if (flag == FALSE) return TPM_BAD_PARAMETER;
tpmData.stclear.flags.disableForceClear = TRUE;
return TPM_SUCCESS;
}
return TPM_BAD_PARAMETER;
}
static TPM_RESULT set_stany_flags(UINT32 subCap, BOOL flag, BOOL ownerAuth,
BOOL deactivated, BOOL disabled)
{
switch (subCap) {
case 2:
if (tpmData.stany.flags.localityModifier
& (TPM_LOC_THREE | TPM_LOC_FOUR)) return TPM_BAD_LOCALITY;
if (deactivated) return TPM_DEACTIVATED;
if (disabled) return TPM_DISABLED;
if (flag == TRUE) return TPM_BAD_PARAMETER;
tpmData.stany.flags.TOSPresent = FALSE;
return TPM_SUCCESS;
}
return TPM_BAD_PARAMETER;
}
static TPM_RESULT set_perm_data(UINT32 subCap, BYTE *setValue,
UINT32 setValueSize, BOOL ownerAuth,
BOOL deactivated, BOOL disabled)
{
TPM_CMK_DELEGATE del;
TPM_NONCE nonce;
switch (subCap) {
case 16:
if (tpmConf & TPM_CONF_ALLOW_PRNG_STATE_SETTING) {
if (setValueSize != sizeof(tpmData.permanent.data.rngState))
return TPM_BAD_PARAMETER;
memcpy(&tpmData.permanent.data.rngState, setValue, setValueSize);
return TPM_SUCCESS;
} else {
return TPM_BAD_PARAMETER;
}
case 23:
if (!ownerAuth) return TPM_AUTHFAIL;
if (deactivated) return TPM_DEACTIVATED;
if (disabled) return TPM_DISABLED;
if (tpm_unmarshal_TPM_CMK_DELEGATE(&setValue, &setValueSize, &del) != 0)
return TPM_BAD_PARAMETER;
tpmData.permanent.data.restrictDelegate = del;
return TPM_SUCCESS;
case 25:
if (!ownerAuth) return TPM_AUTHFAIL;
if (tpm_unmarshal_TPM_NONCE(&setValue, &setValueSize, &nonce) != 0)
return TPM_BAD_PARAMETER;
memcpy(&tpmData.permanent.data.daaProof, &nonce, sizeof(TPM_NONCE));
return TPM_SUCCESS;
}
return TPM_BAD_PARAMETER;
}
static TPM_RESULT set_stclear_data(UINT32 subCap, BYTE *setValue,
UINT32 setValueSize, BOOL ownerAuth,
BOOL deactivated, BOOL disabled)
{
UINT32 presence;
switch (subCap) {
case 23:
if (tpm_unmarshal_UINT32(&setValue, &setValueSize, &presence) != 0)
return TPM_BAD_PARAMETER;
/* without physical presence we are only allowed to disable bits */
if (((tpmData.stclear.data.deferredPhysicalPresence | presence)
!= tpmData.stclear.data.deferredPhysicalPresence)
&& !tpm_get_physical_presence()) return TPM_BAD_PARAMETER;
tpmData.stclear.data.deferredPhysicalPresence = presence;
return TPM_SUCCESS;
}
return TPM_BAD_PARAMETER;
}
static TPM_RESULT set_stany_data(UINT32 subCap, BYTE *setValue,
UINT32 setValueSize, BOOL ownerAuth,
BOOL deactivated, BOOL disabled)
{
return TPM_BAD_PARAMETER;
}
static TPM_RESULT set_vendor(UINT32 subCap, BYTE *setValue,
UINT32 setValueSize, BOOL ownerAuth,
BOOL deactivated, BOOL disabled)
{
/* set the capability area with the specified data, on failure
deactivate the TPM */
switch (subCap) {
case TPM_SET_PERM_FLAGS:
debug("[TPM_SET_PERM_FLAGS]");
if (tpm_unmarshal_TPM_PERMANENT_FLAGS(&setValue, &setValueSize,
&tpmData.permanent.flags) != 0) {
tpmData.stclear.flags.deactivated = TRUE;
return TPM_BAD_PARAMETER;
}
return TPM_SUCCESS;
case TPM_SET_STCLEAR_FLAGS:
debug("[TPM_SET_STCLEAR_FLAGS]");
if (tpm_unmarshal_TPM_STCLEAR_FLAGS(&setValue, &setValueSize,
&tpmData.stclear.flags) != 0) {
tpmData.stclear.flags.deactivated = TRUE;
return TPM_BAD_PARAMETER;
}
return TPM_SUCCESS;
case TPM_SET_STANY_FLAGS:
debug("[TPM_SET_STANY_FLAGS]");
if (tpm_unmarshal_TPM_STANY_FLAGS(&setValue, &setValueSize,
&tpmData.stany.flags) != 0) {
tpmData.stclear.flags.deactivated = TRUE;
return TPM_BAD_PARAMETER;
}
return TPM_SUCCESS;
case TPM_SET_PERM_DATA:
debug("[TPM_SET_PERM_DATA]");
if (tpm_unmarshal_TPM_PERMANENT_DATA(&setValue, &setValueSize,
&tpmData.permanent.data) != 0) {
tpmData.stclear.flags.deactivated = TRUE;
return TPM_BAD_PARAMETER;
}
return TPM_SUCCESS;
case TPM_SET_STCLEAR_DATA:
debug("[TPM_SET_STCLEAR_DATA]");
if (tpm_unmarshal_TPM_STCLEAR_DATA(&setValue, &setValueSize,
&tpmData.stclear.data) != 0) {
tpmData.stclear.flags.deactivated = TRUE;
return TPM_BAD_PARAMETER;
}
return TPM_SUCCESS;
case TPM_SET_STANY_DATA:
debug("[TPM_SET_STANY_DATA]");
if (tpm_unmarshal_TPM_STANY_DATA(&setValue, &setValueSize,
&tpmData.stany.data) != 0) {
tpmData.stclear.flags.deactivated = TRUE;
return TPM_BAD_PARAMETER;
}
return TPM_SUCCESS;
}
return TPM_BAD_PARAMETER;
}
TPM_RESULT TPM_SetCapability(TPM_CAPABILITY_AREA capArea, UINT32 subCapSize,
BYTE *subCap, UINT32 setValueSize, BYTE *setValue,
TPM_AUTH *auth1)
{
TPM_RESULT res;
BOOL ownerAuth = FALSE;
UINT32 subCapVal;
BOOL deactivated = tpmData.permanent.flags.deactivated
|| tpmData.stclear.flags.deactivated;
BOOL disabled = tpmData.permanent.flags.disable;
info("TPM_SetCapability()");
/* verify owner authorization if TPM_TAG_RQU_AUTH1_COMMAND */
if (auth1->authHandle != TPM_INVALID_HANDLE) {
res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER);
if (res != TPM_SUCCESS) return res;
ownerAuth = TRUE;
}
/* unmarshal subCap */
if (tpm_unmarshal_UINT32(&subCap, &subCapSize, &subCapVal) != 0)
return TPM_BAD_PARAMETER;
/* set capability area */
switch (capArea) {
case TPM_SET_PERM_FLAGS:
debug("[TPM_SET_PERM_FLAGS]:%d", subCapVal);
if (setValueSize != 1 || setValue[0] & 0xfe) return TPM_BAD_PARAMETER;
return set_perm_flags(subCapVal, setValue[0], ownerAuth,
deactivated, disabled);
case TPM_SET_STCLEAR_FLAGS:
debug("[TPM_SET_STCLEAR_FLAGS]:%d", subCapVal);
if (setValueSize != 1 || setValue[0] & 0xfe) return TPM_BAD_PARAMETER;
return set_stclear_flags(subCapVal, setValue[0], ownerAuth,
deactivated, disabled);
case TPM_SET_STANY_FLAGS:
debug("[TPM_SET_STANY_FLAGS]:%d", subCapVal);
if (setValueSize != 1 || setValue[0] & 0xfe) return TPM_BAD_PARAMETER;
return set_stany_flags(subCapVal, setValue[0], ownerAuth,
deactivated, disabled);
case TPM_SET_PERM_DATA:
debug("[TPM_SET_PERM_DATA]:%d", subCapVal);
return set_perm_data(subCapVal, setValue, setValueSize, ownerAuth,
deactivated, disabled);
case TPM_SET_STCLEAR_DATA:
debug("[TPM_SET_STCLEAR_DATA]:%d", subCapVal);
return set_stclear_data(subCapVal, setValue, setValueSize, ownerAuth,
deactivated, disabled);
case TPM_SET_STANY_DATA:
debug("[TPM_SET_STANY_DATA]:%d", subCapVal);
return set_stany_data(subCapVal, setValue, setValueSize, ownerAuth,
deactivated, disabled);
case TPM_SET_VENDOR:
debug("[TPM_SET_VENDOR]:%d", subCapVal);
return set_vendor(subCapVal, setValue, setValueSize, ownerAuth,
deactivated, disabled);
}
return TPM_BAD_PARAMETER;
}
TPM_RESULT TPM_GetCapabilityOwner(TPM_AUTH *auth1, TPM_VERSION *version,
UINT32 *non_volatile_flags,
UINT32 *volatile_flags)
{
TPM_RESULT res;
info("TPM_GetCapabilityOwner()");
/* verify owner authorization */
res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER);
if (res != TPM_SUCCESS) return res;
/* initialize */
*version = tpmData.permanent.data.version;
*non_volatile_flags = *volatile_flags = 0;
/* set non-volatile flags */
if (tpmData.permanent.flags.disable)
*non_volatile_flags |= (1 << 0);
if (tpmData.permanent.flags.ownership)
*non_volatile_flags |= (1 << 1);
if (tpmData.permanent.flags.deactivated)
*non_volatile_flags |= (1 << 2);
if (tpmData.permanent.flags.readPubek)
*non_volatile_flags |= (1 << 3);
if (tpmData.permanent.flags.disableOwnerClear)
*non_volatile_flags |= (1 << 4);
if (tpmData.permanent.flags.allowMaintenance)
*non_volatile_flags |= (1 << 5);
if (tpmData.permanent.flags.physicalPresenceLifetimeLock)
*non_volatile_flags |= (1 << 6);
if (tpmData.permanent.flags.physicalPresenceHWEnable)
*non_volatile_flags |= (1 << 7);
if (tpmData.permanent.flags.physicalPresenceCMDEnable)
*non_volatile_flags |= (1 << 8);
if (tpmData.permanent.flags.CEKPUsed)
*non_volatile_flags |= (1 << 9);
if (tpmData.permanent.flags.TPMpost)
*non_volatile_flags |= (1 << 10);
if (tpmData.permanent.flags.TPMpostLock)
*non_volatile_flags |= (1 << 11);
if (tpmData.permanent.flags.FIPS)
*non_volatile_flags |= (1 << 12);
if (tpmData.permanent.flags.operator)
*non_volatile_flags |= (1 << 13);
if (tpmData.permanent.flags.enableRevokeEK)
*non_volatile_flags |= (1 << 14);
if (tpmData.permanent.flags.nvLocked)
*non_volatile_flags |= (1 << 15);
if (tpmData.permanent.flags.readSRKPub)
*non_volatile_flags |= (1 << 16);
if (tpmData.permanent.flags.tpmEstablished)
*non_volatile_flags |= (1 << 17);
if (tpmData.permanent.flags.maintenanceDone)
*non_volatile_flags |= (1 << 18);
if (tpmData.permanent.flags.disableFullDALogicInfo)
*non_volatile_flags |= (1 << 19);
/* set volatile flags */
if (tpmData.stclear.flags.deactivated)
*volatile_flags |= (1 << 0);
if (tpmData.stclear.flags.disableForceClear)
*volatile_flags |= (1 << 1);
if (tpmData.stclear.flags.physicalPresence)
*volatile_flags |= (1 << 2);
if (tpmData.stclear.flags.physicalPresenceLock)
*volatile_flags |= (1 << 3);
if (tpmData.stclear.flags.bGlobalLock)
*volatile_flags |= (1 << 4);
return TPM_SUCCESS;
}