blob: e28580f2d3f356e346076b8e9b0f9b61ec042106 [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_authorization.c 367 2010-02-13 15:52:18Z mast $
*/
#include "tpm_emulator.h"
#include "tpm_commands.h"
#include "tpm_handles.h"
#include "tpm_data.h"
#include "tpm_marshalling.h"
#include "crypto/hmac.h"
#include "crypto/sha1.h"
/*
* Authorization Changing ([TPM_Part3], Section 17)
*/
TPM_RESULT TPM_ChangeAuth(TPM_KEY_HANDLE parentHandle,
TPM_PROTOCOL_ID protocolID, TPM_ENCAUTH *newAuth,
TPM_ENTITY_TYPE entityType, UINT32 encDataSize,
BYTE *encData, TPM_AUTH *auth1, TPM_AUTH *auth2,
UINT32 *outDataSize, BYTE **outData)
{
TPM_RESULT res;
TPM_KEY_DATA *parent;
TPM_SESSION_DATA *session;
TPM_SECRET plainAuth;
info("TPM_ChangeAuth()");
/* get parent key */
parent = tpm_get_key(parentHandle);
if (parent == NULL) return TPM_INVALID_KEYHANDLE;
/* verify entity authorization */
auth2->continueAuthSession = FALSE;
session = tpm_get_auth(auth2->authHandle);
if (session->type != TPM_ST_OIAP) return TPM_BAD_MODE;
/* verify parent authorization */
res = tpm_verify_auth(auth1, parent->usageAuth, parentHandle);
if (res != TPM_SUCCESS) return res;
auth1->continueAuthSession = FALSE;
session = tpm_get_auth(auth1->authHandle);
if (session->type != TPM_ST_OSAP) return TPM_BAD_MODE;
/* decrypt auth */
tpm_decrypt_auth_secret(*newAuth, session->sharedSecret,
&session->lastNonceEven, plainAuth);
/* decrypt the entity, replace authData, and encrypt it again */
if (entityType == TPM_ET_DATA) {
TPM_SEALED_DATA seal;
BYTE *seal_buf;
/* decrypt entity */
if (tpm_decrypt_sealed_data(parent, encData, encDataSize,
&seal, &seal_buf)) return TPM_DECRYPT_ERROR;
/* verify auth2 */
res = tpm_verify_auth(auth2, seal.authData, TPM_INVALID_HANDLE);
if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res;
/* change authData and use it also for auth2 */
memcpy(seal.authData, plainAuth, sizeof(TPM_SECRET));
/* encrypt entity */
*outDataSize = parent->key.size >> 3;
*outData = tpm_malloc(*outDataSize);
if (tpm_encrypt_sealed_data(parent, &seal, *outData, outDataSize)) {
tpm_free(encData);
tpm_free(seal_buf);
return TPM_ENCRYPT_ERROR;
}
tpm_free(seal_buf);
} else if (entityType == TPM_ET_KEY) {
TPM_STORE_ASYMKEY store;
BYTE *store_buf;
/* decrypt entity */
if (tpm_decrypt_private_key(parent, encData, encDataSize,
&store, &store_buf, NULL)) return TPM_DECRYPT_ERROR;
/* verify auth2 */
res = tpm_verify_auth(auth2, store.usageAuth, TPM_INVALID_HANDLE);
if (res != TPM_SUCCESS) return (res == TPM_AUTHFAIL) ? TPM_AUTH2FAIL : res;
/* change usageAuth and use it also for auth2 */
memcpy(store.usageAuth, plainAuth, sizeof(TPM_SECRET));
/* encrypt entity */
*outDataSize = parent->key.size >> 3;
*outData = tpm_malloc(*outDataSize);
if (tpm_encrypt_private_key(parent, &store, *outData, outDataSize)) {
tpm_free(encData);
tpm_free(store_buf);
return TPM_ENCRYPT_ERROR;
}
tpm_free(store_buf);
} else {
return TPM_WRONG_ENTITYTYPE;
}
return TPM_SUCCESS;
}
TPM_RESULT TPM_ChangeAuthOwner(TPM_PROTOCOL_ID protocolID,
TPM_ENCAUTH *newAuth,
TPM_ENTITY_TYPE entityType, TPM_AUTH *auth1)
{
TPM_RESULT res;
TPM_SESSION_DATA *session;
TPM_SECRET plainAuth;
int i;
info("TPM_ChangeAuthOwner()");
/* verify authorization */
res = tpm_verify_auth(auth1, tpmData.permanent.data.ownerAuth, TPM_KH_OWNER);
if (res != TPM_SUCCESS) return res;
auth1->continueAuthSession = FALSE;
session = tpm_get_auth(auth1->authHandle);
if (session->type != TPM_ST_OSAP) return TPM_AUTHFAIL;
/* decrypt auth */
tpm_decrypt_auth_secret(*newAuth, session->sharedSecret,
&session->lastNonceEven, plainAuth);
/* change authorization data */
if (entityType == TPM_ET_OWNER) {
memcpy(tpmData.permanent.data.ownerAuth, plainAuth, sizeof(TPM_SECRET));
/* invalidate all associated sessions but the current one */
for (i = 0; i < TPM_MAX_SESSIONS; i++) {
if (tpmData.stany.data.sessions[i].handle == TPM_KH_OWNER
&& &tpmData.stany.data.sessions[i] != session) {
memset(&tpmData.stany.data.sessions[i], 0, sizeof(TPM_SESSION_DATA));
}
}
} else if (entityType == TPM_ET_SRK) {
memcpy(tpmData.permanent.data.srk.usageAuth, plainAuth, sizeof(TPM_SECRET));
/* probably not correct; spec. v1.2 rev94 says nothing about authDataUsage
tpmData.permanent.data.srk.authDataUsage = TPM_AUTH_ALWAYS;
*/
/* invalidate all associated sessions but the current one */
for (i = 0; i < TPM_MAX_SESSIONS; i++) {
if (tpmData.stany.data.sessions[i].handle == TPM_KH_SRK
&& &tpmData.stany.data.sessions[i] != session) {
memset(&tpmData.stany.data.sessions[i], 0, sizeof(TPM_SESSION_DATA));
}
}
} else {
return TPM_WRONG_ENTITYTYPE;
}
return TPM_SUCCESS;
}
/*
* Authorization Sessions ([TPM_Part3], Section 18)
*/
TPM_RESULT TPM_OIAP(TPM_AUTHHANDLE *authHandle, TPM_NONCE *nonceEven)
{
TPM_SESSION_DATA *session;
info("TPM_OIAP()");
/* get a free session if any is left */
*authHandle = tpm_get_free_session(TPM_ST_OIAP);
session = tpm_get_auth(*authHandle);
if (session == NULL) return TPM_RESOURCES;
/* setup session */
tpm_get_random_bytes(nonceEven->nonce, sizeof(nonceEven->nonce));
memcpy(&session->nonceEven, nonceEven, sizeof(TPM_NONCE));
debug("handle = %08x", *authHandle);
return TPM_SUCCESS;
}
TPM_RESULT TPM_OSAP(TPM_ENTITY_TYPE entityType, UINT32 entityValue,
TPM_NONCE *nonceOddOSAP, TPM_AUTHHANDLE *authHandle,
TPM_NONCE *nonceEven, TPM_NONCE *nonceEvenOSAP)
{
tpm_hmac_ctx_t ctx;
TPM_SESSION_DATA *session;
TPM_SECRET *secret = NULL;
info("TPM_OSAP()");
/* get a free session if any is left */
*authHandle = tpm_get_free_session(TPM_ST_OSAP);
session = tpm_get_auth(*authHandle);
if (session == NULL) return TPM_RESOURCES;
debug("entityType = %04x, entityValue = %04x", entityType, entityValue);
/* check whether ADIP encryption scheme is supported */
switch (entityType & 0xFF00) {
case TPM_ET_XOR:
break;
default:
return TPM_INAPPROPRIATE_ENC;
}
/* get resource handle and the respective secret */
switch (entityType & 0x00FF) {
case TPM_ET_KEYHANDLE:
session->handle = entityValue;
if (session->handle == TPM_KH_OPERATOR) return TPM_BAD_HANDLE;
if (tpm_get_key(session->handle) != NULL)
secret = &tpm_get_key(session->handle)->usageAuth;
else
debug("TPM_OSAP failed(): tpm_get_key(handle) == NULL");
break;
case TPM_ET_OWNER:
case TPM_ET_VERIFICATION_AUTH:
session->handle = TPM_KH_OWNER;
if (tpmData.permanent.flags.owned)
secret = &tpmData.permanent.data.ownerAuth;
break;
case TPM_ET_SRK:
session->handle = TPM_KH_SRK;
if (tpmData.permanent.data.srk.payload)
secret = &tpmData.permanent.data.srk.usageAuth;
break;
case TPM_ET_COUNTER:
session->handle = entityValue;
if (tpm_get_counter(session->handle) != NULL)
secret = &tpm_get_counter(session->handle)->usageAuth;
break;
case TPM_ET_NV:
session->handle = entityValue;
if (tpm_get_nvs(session->handle) != NULL)
secret = &tpm_get_nvs(session->handle)->authValue;
break;
default:
return TPM_BAD_PARAMETER;
}
if (secret == NULL) {
debug("TPM_OSAP failed(): secret == NULL");
memset(session, 0, sizeof(*session));
return TPM_BAD_PARAMETER;
}
/* save entity type */
session->entityType = entityType;
/* generate nonces */
tpm_get_random_bytes(nonceEven->nonce, sizeof(nonceEven->nonce));
memcpy(&session->nonceEven, nonceEven, sizeof(TPM_NONCE));
tpm_get_random_bytes(nonceEvenOSAP->nonce, sizeof(nonceEvenOSAP->nonce));
/* compute shared secret */
tpm_hmac_init(&ctx, *secret, sizeof(*secret));
tpm_hmac_update(&ctx, nonceEvenOSAP->nonce, sizeof(nonceEvenOSAP->nonce));
tpm_hmac_update(&ctx, nonceOddOSAP->nonce, sizeof(nonceOddOSAP->nonce));
tpm_hmac_final(&ctx, session->sharedSecret);
debug("handle = %08x", *authHandle);
return TPM_SUCCESS;
}
TPM_RESULT TPM_DSAP(TPM_ENTITY_TYPE entityType, TPM_KEY_HANDLE keyHandle,
TPM_NONCE *nonceOddDSAP, UINT32 entityValueSize,
BYTE *entityValue, TPM_AUTHHANDLE *authHandle,
TPM_NONCE *nonceEven, TPM_NONCE *nonceEvenDSAP)
{
tpm_hmac_ctx_t ctx;
TPM_SESSION_DATA *session;
TPM_SECRET secret;
TPM_FAMILY_TABLE_ENTRY *fr;
info("TPM_DSAP()");
/* get a free session if any is left */
*authHandle = tpm_get_free_session(TPM_ST_DSAP);
session = tpm_get_auth(*authHandle);
if (session == NULL) return TPM_RESOURCES;
debug("entityType = %04x, entityValueSize = %04x", entityType, entityValueSize);
/* decode entity value and get respective secret */
if (entityType == TPM_ET_DEL_OWNER_BLOB) {
TPM_DELEGATE_OWNER_BLOB blob;
TPM_DELEGATE_SENSITIVE sens;
BYTE *sens_buf;
TPM_DIGEST blobDigest;
/* unmarshal the entity value */
if (tpm_unmarshal_TPM_DELEGATE_OWNER_BLOB(&entityValue,
&entityValueSize, &blob)
|| blob.tag != TPM_TAG_DELEGATE_OWNER_BLOB) return TPM_WRONG_ENTITYTYPE;
/* validate the integrity of the blob */
tpm_compute_owner_blob_digest(&blob, &blobDigest);
if (memcmp(&blob.integrityDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0)
return TPM_AUTHFAIL;
/* get family table row */
debug("family id = %d", blob.pub.familyID);
fr = tpm_get_family_row(blob.pub.familyID);
if (fr == NULL) return TPM_BADINDEX;
if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD;
if (fr->verificationCount != blob.pub.verificationCount) return TPM_FAIL;
/* decrypt sensitive data */
if (tpm_decrypt_sensitive(blob.additionalArea, blob.additionalSize,
blob.sensitiveArea, blob.sensitiveSize, &sens, &sens_buf)) {
debug("tpm_decrypt_sensitive() failed");
return TPM_DECRYPT_ERROR;
}
if (sens.tag != TPM_TAG_DELEGATE_SENSITIVE) {
tpm_free(sens_buf);
return TPM_BAD_DELEGATE;
}
memcpy(&secret, &sens.authValue, sizeof(TPM_SECRET));
memcpy(&session->permissions, &blob.pub.permissions, sizeof(TPM_DELEGATIONS));
session->handle = TPM_KH_OWNER;
session->familyID = blob.pub.familyID;
tpm_free(sens_buf);
} else if (entityType == TPM_ET_DEL_ROW) {
UINT32 row;
TPM_DELEGATE_TABLE_ROW *dr;
if (tpm_unmarshal_UINT32(&entityValue, &entityValueSize, &row))
return TPM_WRONG_ENTITYTYPE;
debug("row number = %d", row);
dr = tpm_get_delegate_row(row);
if (dr == NULL) return TPM_BADINDEX;
fr = tpm_get_family_row(dr->pub.familyID);
if (fr == NULL) return TPM_BADINDEX;
if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD;
if (fr->verificationCount != dr->pub.verificationCount) return TPM_FAIL;
memcpy(&secret, dr->authValue, sizeof(TPM_SECRET));
memcpy(&session->permissions, &dr->pub.permissions, sizeof(TPM_DELEGATIONS));
session->handle = keyHandle;
session->familyID = dr->pub.familyID;
} else if (entityType == TPM_ET_DEL_KEY_BLOB) {
TPM_DELEGATE_KEY_BLOB blob;
TPM_DELEGATE_SENSITIVE sens;
BYTE *sens_buf;
TPM_DIGEST blobDigest;
TPM_KEY_DATA *key;
TPM_PUBKEY pubKey;
/* unmarshal the entity value */
if (tpm_unmarshal_TPM_DELEGATE_KEY_BLOB(&entityValue,
&entityValueSize, &blob)
|| blob.tag != TPM_TAG_DELEGATE_KEY_BLOB) return TPM_WRONG_ENTITYTYPE;
/* validate the integrity of the blob */
tpm_compute_key_blob_digest(&blob, &blobDigest);
if (memcmp(&blob.integrityDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0)
return TPM_AUTHFAIL;
/* validate key digest */
key = tpm_get_key(keyHandle);
if (key == NULL) return TPM_KEYNOTFOUND;
if (tpm_extract_pubkey(key, &pubKey) != 0) {
debug("tpm_extract_pubkey() failed.");
return TPM_FAIL;
}
if (tpm_compute_pubkey_digest(&pubKey, &blobDigest) != 0) {
debug("tpm_compute_pubkey_digest() failed.");
free_TPM_PUBKEY(pubKey);
return TPM_FAIL;
}
free_TPM_PUBKEY(pubKey);
if (memcmp(&blob.pubKeyDigest, &blobDigest, sizeof(TPM_DIGEST)) != 0)
return TPM_KEYNOTFOUND;
/* get family table row */
debug("family id = %d", blob.pub.familyID);
fr = tpm_get_family_row(blob.pub.familyID);
if (fr == NULL) return TPM_BADINDEX;
if (!(fr->flags & TPM_FAMFLAG_ENABLED)) return TPM_DISABLED_CMD;
if (fr->verificationCount != blob.pub.verificationCount) return TPM_FAIL;
/* decrypt sensitive data */
if (tpm_decrypt_sensitive(blob.additionalArea, blob.additionalSize,
blob.sensitiveArea, blob.sensitiveSize, &sens, &sens_buf)) {
debug("tpm_decrypt_sensitive() failed");
return TPM_DECRYPT_ERROR;
}
if (sens.tag != TPM_TAG_DELEGATE_SENSITIVE) {
tpm_free(sens_buf);
return TPM_BAD_DELEGATE;
}
memcpy(&secret, &sens.authValue, sizeof(TPM_SECRET));
memcpy(&session->permissions, &blob.pub.permissions, sizeof(TPM_DELEGATIONS));
session->handle = keyHandle;
session->familyID = blob.pub.familyID;
tpm_free(sens_buf);
} else {
return TPM_BAD_PARAMETER;
}
/* save entity type */
session->entityType = entityType;
/* generate nonces */
tpm_get_random_bytes(nonceEven->nonce, sizeof(nonceEven->nonce));
memcpy(&session->nonceEven, nonceEven, sizeof(TPM_NONCE));
tpm_get_random_bytes(nonceEvenDSAP->nonce, sizeof(nonceEvenDSAP->nonce));
/* compute shared secret */
tpm_hmac_init(&ctx, secret, sizeof(secret));
tpm_hmac_update(&ctx, nonceEvenDSAP->nonce, sizeof(nonceEvenDSAP->nonce));
tpm_hmac_update(&ctx, nonceOddDSAP->nonce, sizeof(nonceOddDSAP->nonce));
tpm_hmac_final(&ctx, session->sharedSecret);
debug("handle = %08x", *authHandle);
return TPM_SUCCESS;
}
TPM_RESULT TPM_SetOwnerPointer(TPM_ENTITY_TYPE entityType, UINT32 entityValue)
{
info("TPM_SetOwnerPointer() is not supported");
return TPM_DISABLED_CMD;
}
#define IS_SET(val, mask) (((val) & (mask)) == (mask))
static BOOL is_owner_delegation_permitted(TPM_COMMAND_CODE ordinal,
UINT32 per1, UINT32 per2)
{
switch (ordinal) {
case TPM_ORD_SetOrdinalAuditStatus:
return IS_SET(per1, TPM_DELEGATE_SetOrdinalAuditStatus);
case TPM_ORD_DirWriteAuth:
return IS_SET(per1, TPM_DELEGATE_DirWriteAuth);
case TPM_ORD_CMK_ApproveMA:
return IS_SET(per1, TPM_DELEGATE_CMK_ApproveMA);
case TPM_ORD_NV_WriteValue:
return IS_SET(per1, TPM_DELEGATE_NV_WriteValue);
case TPM_ORD_CMK_CreateTicket:
return IS_SET(per1, TPM_DELEGATE_CMK_CreateTicket);
case TPM_ORD_NV_ReadValue:
return IS_SET(per1, TPM_DELEGATE_NV_ReadValue);
case TPM_ORD_Delegate_LoadOwnerDelegation:
return IS_SET(per1, TPM_DELEGATE_Delegate_LoadOwnerDelegation);
case TPM_ORD_DAA_Join:
return IS_SET(per1, TPM_DELEGATE_DAA_Join);
case TPM_ORD_AuthorizeMigrationKey:
return IS_SET(per1, TPM_DELEGATE_AuthorizeMigrationKey);
case TPM_ORD_CreateMaintenanceArchive:
return IS_SET(per1, TPM_DELEGATE_CreateMaintenanceArchive);
case TPM_ORD_LoadMaintenanceArchive:
return IS_SET(per1, TPM_DELEGATE_LoadMaintenanceArchive);
case TPM_ORD_KillMaintenanceFeature:
return IS_SET(per1, TPM_DELEGATE_KillMaintenanceFeature);
case TPM_ORD_OwnerReadInternalPub:
return IS_SET(per1, TPM_DELEGATE_OwnerReadInternalPub);
case TPM_ORD_ResetLockValue:
return IS_SET(per1, TPM_DELEGATE_ResetLockValue);
case TPM_ORD_OwnerClear:
return IS_SET(per1, TPM_DELEGATE_OwnerClear);
case TPM_ORD_DisableOwnerClear:
return IS_SET(per1, TPM_DELEGATE_DisableOwnerClear);
case TPM_ORD_NV_DefineSpace:
return IS_SET(per1, TPM_DELEGATE_NV_DefineSpace);
case TPM_ORD_OwnerSetDisable:
return IS_SET(per1, TPM_DELEGATE_OwnerSetDisable);
case TPM_ORD_SetCapability:
return IS_SET(per1, TPM_DELEGATE_SetCapability);
case TPM_ORD_MakeIdentity:
return IS_SET(per1, TPM_DELEGATE_MakeIdentity);
case TPM_ORD_ActivateIdentity:
return IS_SET(per1, TPM_DELEGATE_ActivateIdentity);
case TPM_ORD_OwnerReadPubek:
return IS_SET(per1, TPM_DELEGATE_OwnerReadPubek);
case TPM_ORD_DisablePubekRead:
return IS_SET(per1, TPM_DELEGATE_DisablePubekRead);
case TPM_ORD_SetRedirection:
return IS_SET(per1, TPM_DELEGATE_SetRedirection);
case TPM_ORD_FieldUpgrade:
return IS_SET(per1, TPM_DELEGATE_FieldUpgrade);
case TPM_ORD_Delegate_UpdateVerification:
return IS_SET(per1, TPM_DELEGATE_Delegate_UpdateVerification);
case TPM_ORD_CreateCounter:
return IS_SET(per1, TPM_DELEGATE_CreateCounter);
case TPM_ORD_ReleaseCounterOwner:
return IS_SET(per1, TPM_DELEGATE_ReleaseCounterOwner);
case TPM_ORD_Delegate_Manage:
return IS_SET(per1, TPM_DELEGATE_Delegate_Manage);
case TPM_ORD_Delegate_CreateOwnerDelegation:
return IS_SET(per1, TPM_DELEGATE_Delegate_CreateOwnerDelegation);
case TPM_ORD_DAA_Sign:
return IS_SET(per1, TPM_DELEGATE_DAA_Sign);
}
return FALSE;
}
static BOOL is_key_delegation_permitted(TPM_COMMAND_CODE ordinal,
UINT32 per1, UINT32 per2)
{
switch (ordinal) {
case TPM_ORD_CMK_ConvertMigration:
return IS_SET(per1, TPM_KEY_DELEGATE_CMK_ConvertMigration);
case TPM_ORD_TickStampBlob:
return IS_SET(per1, TPM_KEY_DELEGATE_TickStampBlob);
case TPM_ORD_ChangeAuthAsymStart:
return IS_SET(per1, TPM_KEY_DELEGATE_ChangeAuthAsymStart);
case TPM_ORD_ChangeAuthAsymFinish:
return IS_SET(per1, TPM_KEY_DELEGATE_ChangeAuthAsymFinish);
case TPM_ORD_CMK_CreateKey:
return IS_SET(per1, TPM_KEY_DELEGATE_CMK_CreateKey);
case TPM_ORD_MigrateKey:
return IS_SET(per1, TPM_KEY_DELEGATE_MigrateKey);
case TPM_ORD_LoadKey2:
return IS_SET(per1, TPM_KEY_DELEGATE_LoadKey2);
case TPM_ORD_EstablishTransport:
return IS_SET(per1, TPM_KEY_DELEGATE_EstablishTransport);
case TPM_ORD_ReleaseTransportSigned:
return IS_SET(per1, TPM_KEY_DELEGATE_ReleaseTransportSigned);
case TPM_ORD_Quote2:
return IS_SET(per1, TPM_KEY_DELEGATE_Quote2);
case TPM_ORD_Sealx:
return IS_SET(per1, TPM_KEY_DELEGATE_Sealx);
case TPM_ORD_MakeIdentity:
return IS_SET(per1, TPM_KEY_DELEGATE_MakeIdentity);
case TPM_ORD_ActivateIdentity:
return IS_SET(per1, TPM_KEY_DELEGATE_ActivateIdentity);
case TPM_ORD_GetAuditDigestSigned:
return IS_SET(per1, TPM_KEY_DELEGATE_GetAuditDigestSigned);
case TPM_ORD_Sign:
return IS_SET(per1, TPM_KEY_DELEGATE_Sign);
case TPM_ORD_CertifyKey2:
return IS_SET(per1, TPM_KEY_DELEGATE_CertifyKey2);
case TPM_ORD_CertifyKey:
return IS_SET(per1, TPM_KEY_DELEGATE_CertifyKey);
case TPM_ORD_CreateWrapKey:
return IS_SET(per1, TPM_KEY_DELEGATE_CreateWrapKey);
case TPM_ORD_CMK_CreateBlob:
return IS_SET(per1, TPM_KEY_DELEGATE_CMK_CreateBlob);
case TPM_ORD_CreateMigrationBlob:
return IS_SET(per1, TPM_KEY_DELEGATE_CreateMigrationBlob);
case TPM_ORD_ConvertMigrationBlob:
return IS_SET(per1, TPM_KEY_DELEGATE_ConvertMigrationBlob);
case TPM_ORD_Delegate_CreateKeyDelegation:
return IS_SET(per1, TPM_KEY_DELEGATE_Delegate_CreateKeyDelegation);
case TPM_ORD_ChangeAuth:
return IS_SET(per1, TPM_KEY_DELEGATE_ChangeAuth);
case TPM_ORD_GetPubKey:
return IS_SET(per1, TPM_KEY_DELEGATE_GetPubKey);
case TPM_ORD_Quote:
return IS_SET(per1, TPM_KEY_DELEGATE_Quote);
case TPM_ORD_Unseal:
return IS_SET(per1, TPM_KEY_DELEGATE_Unseal);
case TPM_ORD_Seal:
return IS_SET(per1, TPM_KEY_DELEGATE_Seal);
case TPM_ORD_LoadKey:
return IS_SET(per1, TPM_KEY_DELEGATE_LoadKey);
}
return FALSE;
}
TPM_RESULT tpm_verify_auth(TPM_AUTH *auth, TPM_SECRET secret,
TPM_HANDLE handle)
{
tpm_hmac_ctx_t ctx;
TPM_SESSION_DATA *session;
BYTE digest[SHA1_DIGEST_LENGTH];
info("tpm_verify_auth()");
debug("handle = %08x", auth->authHandle);
/* get dedicated authorization or transport session */
session = tpm_get_auth(auth->authHandle);
if (session == NULL) session = tpm_get_transport(auth->authHandle);
if (session == NULL) return TPM_INVALID_AUTHHANDLE;
/* setup authorization */
if (session->type == TPM_ST_OIAP) {
debug("[TPM_ST_OIAP]");
/* We copy the secret because it might be deleted or invalidated
afterwards, but we need it again for authorizing the response. */
memcpy(session->sharedSecret, secret, sizeof(TPM_SECRET));
} else if (session->type == TPM_ST_OSAP) {
debug("[TPM_ST_OSAP]");
if (session->handle != handle) return TPM_AUTHFAIL;
} else if (session->type == TPM_ST_DSAP) {
debug("[TPM_ST_DSAP]");
if (session->handle != handle) return TPM_AUTHFAIL;
/* check permissions */
debug("delegation type = %d", session->permissions.delegateType);
if (session->permissions.delegateType == TPM_DEL_OWNER_BITS) {
if (!is_owner_delegation_permitted(auth->ordinal,
session->permissions.per1, session->permissions.per2))
return TPM_DISABLED_CMD;
} else if (session->permissions.delegateType == TPM_DEL_KEY_BITS) {
if (!is_key_delegation_permitted(auth->ordinal,
session->permissions.per1, session->permissions.per2))
return TPM_DISABLED_CMD;
} else {
return TPM_AUTHFAIL;
}
} else if (session->type == TPM_ST_TRANSPORT) {
debug("[TPM_ST_TRANSPORT]");
memcpy(session->sharedSecret, session->transInternal.authData,
sizeof(TPM_SECRET));
} else {
return TPM_INVALID_AUTHHANDLE;
}
auth->secret = &session->sharedSecret;
/* verify authorization */
tpm_hmac_init(&ctx, *auth->secret, sizeof(*auth->secret));
tpm_hmac_update(&ctx, auth->digest, sizeof(auth->digest));
tpm_hmac_update(&ctx, session->nonceEven.nonce, sizeof(session->nonceEven.nonce));
tpm_hmac_update(&ctx, auth->nonceOdd.nonce, sizeof(auth->nonceOdd.nonce));
tpm_hmac_update(&ctx, &auth->continueAuthSession, 1);
tpm_hmac_final(&ctx, digest);
if (memcmp(digest, auth->auth, sizeof(auth->auth))) return TPM_AUTHFAIL;
/* generate new nonceEven */
memcpy(&session->lastNonceEven, &session->nonceEven, sizeof(TPM_NONCE));
tpm_get_random_bytes(auth->nonceEven.nonce, sizeof(auth->nonceEven.nonce));
memcpy(&session->nonceEven, &auth->nonceEven, sizeof(TPM_NONCE));
return TPM_SUCCESS;
}
void tpm_decrypt_auth_secret(TPM_ENCAUTH encAuth, TPM_SECRET secret,
TPM_NONCE *nonce, TPM_SECRET plainAuth)
{
unsigned int i;
tpm_sha1_ctx_t ctx;
tpm_sha1_init(&ctx);
tpm_sha1_update(&ctx, secret, sizeof(TPM_SECRET));
tpm_sha1_update(&ctx, nonce->nonce, sizeof(nonce->nonce));
tpm_sha1_final(&ctx, plainAuth);
for (i = 0; i < sizeof(TPM_SECRET); i++)
plainAuth[i] ^= encAuth[i];
}