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