diff options
Diffstat (limited to 'src/tpm2/EACommands.c')
-rw-r--r-- | src/tpm2/EACommands.c | 1164 |
1 files changed, 1164 insertions, 0 deletions
diff --git a/src/tpm2/EACommands.c b/src/tpm2/EACommands.c new file mode 100644 index 0000000..abf6074 --- /dev/null +++ b/src/tpm2/EACommands.c @@ -0,0 +1,1164 @@ +/********************************************************************************/ +/* */ +/* Enhanced Authorization Commands */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: EACommands.c 1519 2019-11-15 20:43:51Z kgoldman $ */ +/* */ +/* Licenses and Notices */ +/* */ +/* 1. Copyright Licenses: */ +/* */ +/* - Trusted Computing Group (TCG) grants to the user of the source code in */ +/* this specification (the "Source Code") a worldwide, irrevocable, */ +/* nonexclusive, royalty free, copyright license to reproduce, create */ +/* derivative works, distribute, display and perform the Source Code and */ +/* derivative works thereof, and to grant others the rights granted herein. */ +/* */ +/* - The TCG grants to the user of the other parts of the specification */ +/* (other than the Source Code) the rights to reproduce, distribute, */ +/* display, and perform the specification solely for the purpose of */ +/* developing products based on such documents. */ +/* */ +/* 2. Source Code Distribution Conditions: */ +/* */ +/* - Redistributions of Source Code must retain the above copyright licenses, */ +/* this list of conditions and the following disclaimers. */ +/* */ +/* - Redistributions in binary form must reproduce the above copyright */ +/* licenses, this list of conditions and the following disclaimers in the */ +/* documentation and/or other materials provided with the distribution. */ +/* */ +/* 3. Disclaimers: */ +/* */ +/* - THE COPYRIGHT LICENSES SET FORTH ABOVE DO NOT REPRESENT ANY FORM OF */ +/* LICENSE OR WAIVER, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, WITH */ +/* RESPECT TO PATENT RIGHTS HELD BY TCG MEMBERS (OR OTHER THIRD PARTIES) */ +/* THAT MAY BE NECESSARY TO IMPLEMENT THIS SPECIFICATION OR OTHERWISE. */ +/* Contact TCG Administration (admin@trustedcomputinggroup.org) for */ +/* information on specification licensing rights available through TCG */ +/* membership agreements. */ +/* */ +/* - THIS SPECIFICATION IS PROVIDED "AS IS" WITH NO EXPRESS OR IMPLIED */ +/* WARRANTIES WHATSOEVER, INCLUDING ANY WARRANTY OF MERCHANTABILITY OR */ +/* FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, COMPLETENESS, OR */ +/* NONINFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS, OR ANY WARRANTY */ +/* OTHERWISE ARISING OUT OF ANY PROPOSAL, SPECIFICATION OR SAMPLE. */ +/* */ +/* - Without limitation, TCG and its members and licensors disclaim all */ +/* liability, including liability for infringement of any proprietary */ +/* rights, relating to use of information in this specification and to the */ +/* implementation of this specification, and TCG disclaims all liability for */ +/* cost of procurement of substitute goods or services, lost profits, loss */ +/* of use, loss of data or any incidental, consequential, direct, indirect, */ +/* or special damages, whether under contract, tort, warranty or otherwise, */ +/* arising in any way out of use or reliance upon this specification or any */ +/* information herein. */ +/* */ +/* (c) Copyright IBM Corp. and others, 2016 - 2019 */ +/* */ +/********************************************************************************/ + +#include "Tpm.h" +#include "Policy_spt_fp.h" +#include "PolicySigned_fp.h" +#if CC_PolicySigned // Conditional expansion of this file +/*TPM_RC_CPHASH cpHash was previously set to a different value */ +/*TPM_RC_EXPIRED expiration indicates a time in the past or expiration is non-zero but no nonceTPM + is present */ +/*TPM_RC_NONCE nonceTPM is not the nonce associated with the policySession */ +/*TPM_RC_SCHEME the signing scheme of auth is not supported by the TPM */ +/*TPM_RC_SIGNATURE the signature is not genuine */ +/*TPM_RC_SIZE input cpHash has wrong size */ +TPM_RC +TPM2_PolicySigned( + PolicySigned_In *in, // IN: input parameter list + PolicySigned_Out *out // OUT: output parameter list + ) +{ + TPM_RC result = TPM_RC_SUCCESS; + SESSION *session; + TPM2B_NAME entityName; + TPM2B_DIGEST authHash; + HASH_STATE hashState; + UINT64 authTimeout = 0; + // Input Validation + // Set up local pointers + session = SessionGet(in->policySession); // the session structure + // Only do input validation if this is not a trial policy session + if(session->attributes.isTrialPolicy == CLEAR) + { + authTimeout = ComputeAuthTimeout(session, in->expiration, &in->nonceTPM); + result = PolicyParameterChecks(session, authTimeout, + &in->cpHashA, &in->nonceTPM, + RC_PolicySigned_nonceTPM, + RC_PolicySigned_cpHashA, + RC_PolicySigned_expiration); + if(result != TPM_RC_SUCCESS) + return result; + // Re-compute the digest being signed + // Start hash + authHash.t.size = CryptHashStart(&hashState, + CryptGetSignHashAlg(&in->auth)); + // If there is no digest size, then we don't have a verification function + // for this algorithm (e.g. TPM_ALG_ECDAA) so indicate that it is a + // bad scheme. + if(authHash.t.size == 0) + return TPM_RCS_SCHEME + RC_PolicySigned_auth; + // nonceTPM + CryptDigestUpdate2B(&hashState, &in->nonceTPM.b); + // expiration + CryptDigestUpdateInt(&hashState, sizeof(UINT32), in->expiration); + // cpHashA + CryptDigestUpdate2B(&hashState, &in->cpHashA.b); + // policyRef + CryptDigestUpdate2B(&hashState, &in->policyRef.b); + // Complete digest + CryptHashEnd2B(&hashState, &authHash.b); + // Validate Signature. A TPM_RC_SCHEME, TPM_RC_HANDLE or TPM_RC_SIGNATURE + // error may be returned at this point + result = CryptValidateSignature(in->authObject, &authHash, &in->auth); + if(result != TPM_RC_SUCCESS) + return RcSafeAddToResult(result, RC_PolicySigned_auth); + } + // Internal Data Update + // Update policy with input policyRef and name of authorization key + // These values are updated even if the session is a trial session + PolicyContextUpdate(TPM_CC_PolicySigned, + EntityGetName(in->authObject, &entityName), + &in->policyRef, + &in->cpHashA, authTimeout, session); + // Command Output + // Create ticket and timeout buffer if in->expiration < 0 and this is not + // a trial session. + // NOTE: PolicyParameterChecks() makes sure that nonceTPM is present + // when expiration is non-zero. + if(in->expiration < 0 + && session->attributes.isTrialPolicy == CLEAR) + { + BOOL expiresOnReset = (in->nonceTPM.t.size == 0); + // Compute policy ticket + authTimeout &= ~EXPIRATION_BIT; + TicketComputeAuth(TPM_ST_AUTH_SIGNED, EntityGetHierarchy(in->authObject), + authTimeout, expiresOnReset, &in->cpHashA, &in->policyRef, + &entityName, &out->policyTicket); + // Generate timeout buffer. The format of output timeout buffer is + // TPM-specific. + // Note: In this implementation, the timeout buffer value is computed after + // the ticket is produced so, when the ticket is checked, the expiration + // flag needs to be extracted before the ticket is checked. + // In the Windows compatible version, the least-significant bit of the + // timeout value is used as a flag to indicate if the authorization expires + // on reset. The flag is the MSb. + out->timeout.t.size = sizeof(authTimeout); + if(expiresOnReset) + authTimeout |= EXPIRATION_BIT; + UINT64_TO_BYTE_ARRAY(authTimeout, out->timeout.t.buffer); + } + else + { + // Generate a null ticket. + // timeout buffer is null + out->timeout.t.size = 0; + // authorization ticket is null + out->policyTicket.tag = TPM_ST_AUTH_SIGNED; + out->policyTicket.hierarchy = TPM_RH_NULL; + out->policyTicket.digest.t.size = 0; + } + return TPM_RC_SUCCESS; +} +#endif // CC_PolicySigned +#include "Tpm.h" +#include "PolicySecret_fp.h" +#if CC_PolicySecret // Conditional expansion of this file +#include "Policy_spt_fp.h" +#include "NV_spt_fp.h" +/* TPM_RC_CPHASH cpHash for policy was previously set to a value that is not the same as cpHashA */ +/* TPM_RC_EXPIRED expiration indicates a time in the past */ +/* TPM_RC_NONCE nonceTPM does not match the nonce associated with policySession */ +/* TPM_RC_SIZE cpHashA is not the size of a digest for the hash associated with policySession */ +TPM_RC +TPM2_PolicySecret( + PolicySecret_In *in, // IN: input parameter list + PolicySecret_Out *out // OUT: output parameter list + ) +{ + TPM_RC result; + SESSION *session; + TPM2B_NAME entityName; + UINT64 authTimeout = 0; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + //Only do input validation if this is not a trial policy session + if(session->attributes.isTrialPolicy == CLEAR) + { + authTimeout = ComputeAuthTimeout(session, in->expiration, &in->nonceTPM); + result = PolicyParameterChecks(session, authTimeout, + &in->cpHashA, &in->nonceTPM, + RC_PolicySecret_nonceTPM, + RC_PolicySecret_cpHashA, + RC_PolicySecret_expiration); + if(result != TPM_RC_SUCCESS) + return result; + } + // Internal Data Update + // Update policy context with input policyRef and name of authorizing key + // This value is computed even for trial sessions. Possibly update the cpHash + PolicyContextUpdate(TPM_CC_PolicySecret, + EntityGetName(in->authHandle, &entityName), &in->policyRef, + &in->cpHashA, authTimeout, session); + // Command Output + // Create ticket and timeout buffer if in->expiration < 0 and this is not + // a trial session. + // NOTE: PolicyParameterChecks() makes sure that nonceTPM is present + // when expiration is non-zero. + if(in->expiration < 0 + && session->attributes.isTrialPolicy == CLEAR + && !NvIsPinPassIndex(in->authHandle)) + { + BOOL expiresOnReset = (in->nonceTPM.t.size == 0); + // Compute policy ticket + authTimeout &= ~EXPIRATION_BIT; + TicketComputeAuth(TPM_ST_AUTH_SECRET, EntityGetHierarchy(in->authHandle), + authTimeout, expiresOnReset, &in->cpHashA, &in->policyRef, + &entityName, &out->policyTicket); + // Generate timeout buffer. The format of output timeout buffer is + // TPM-specific. + // Note: In this implementation, the timeout buffer value is computed after + // the ticket is produced so, when the ticket is checked, the expiration + // flag needs to be extracted before the ticket is checked. + out->timeout.t.size = sizeof(authTimeout); + // In the Windows compatible version, the least-significant bit of the + // timeout value is used as a flag to indicate if the authorization expires + // on reset. The flag is the MSb. + if(expiresOnReset) + authTimeout |= EXPIRATION_BIT; + UINT64_TO_BYTE_ARRAY(authTimeout, out->timeout.t.buffer); + } + else + { + // timeout buffer is null + out->timeout.t.size = 0; + // authorization ticket is null + out->policyTicket.tag = TPM_ST_AUTH_SECRET; + out->policyTicket.hierarchy = TPM_RH_NULL; + out->policyTicket.digest.t.size = 0; + } + return TPM_RC_SUCCESS; +} +#endif // CC_PolicySecret +#include "Tpm.h" +#include "PolicyTicket_fp.h" +#if CC_PolicyTicket // Conditional expansion of this file +#include "Policy_spt_fp.h" +/* TPM_RC_CPHASH policy's cpHash was previously set to a different value */ +/* TPM_RC_EXPIRED timeout value in the ticket is in the past and the ticket has expired */ +/* TPM_RC_SIZE timeout or cpHash has invalid size for the */ +/* TPM_RC_TICKET ticket is not valid */ +TPM_RC +TPM2_PolicyTicket( + PolicyTicket_In *in // IN: input parameter list + ) +{ + TPM_RC result; + SESSION *session; + UINT64 authTimeout; + TPMT_TK_AUTH ticketToCompare; + TPM_CC commandCode = TPM_CC_PolicySecret; + BOOL expiresOnReset; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + // NOTE: A trial policy session is not allowed to use this command. + // A ticket is used in place of a previously given authorization. Since + // a trial policy doesn't actually authenticate, the validated + // ticket is not necessary and, in place of using a ticket, one + // should use the intended authorization for which the ticket + // would be a substitute. + if(session->attributes.isTrialPolicy) + return TPM_RCS_ATTRIBUTES + RC_PolicyTicket_policySession; + // Restore timeout data. The format of timeout buffer is TPM-specific. + // In this implementation, the most significant bit of the timeout value is + // used as the flag to indicate that the ticket expires on TPM Reset or + // TPM Restart. The flag has to be removed before the parameters and ticket + // are checked. + if(in->timeout.t.size != sizeof(UINT64)) + return TPM_RCS_SIZE + RC_PolicyTicket_timeout; + authTimeout = BYTE_ARRAY_TO_UINT64(in->timeout.t.buffer); + // extract the flag + expiresOnReset = (authTimeout & EXPIRATION_BIT) != 0; + authTimeout &= ~EXPIRATION_BIT; + // Do the normal checks on the cpHashA and timeout values + result = PolicyParameterChecks(session, authTimeout, + &in->cpHashA, + NULL, // no nonce + 0, // no bad nonce return + RC_PolicyTicket_cpHashA, + RC_PolicyTicket_timeout); + if(result != TPM_RC_SUCCESS) + return result; + // Validate Ticket + // Re-generate policy ticket by input parameters + TicketComputeAuth(in->ticket.tag, in->ticket.hierarchy, + authTimeout, expiresOnReset, &in->cpHashA, &in->policyRef, + &in->authName, &ticketToCompare); + // Compare generated digest with input ticket digest + if(!MemoryEqual2B(&in->ticket.digest.b, &ticketToCompare.digest.b)) + return TPM_RCS_TICKET + RC_PolicyTicket_ticket; + // Internal Data Update + // Is this ticket to take the place of a TPM2_PolicySigned() or + // a TPM2_PolicySecret()? + if(in->ticket.tag == TPM_ST_AUTH_SIGNED) + commandCode = TPM_CC_PolicySigned; + else if(in->ticket.tag == TPM_ST_AUTH_SECRET) + commandCode = TPM_CC_PolicySecret; + else + // There could only be two possible tag values. Any other value should + // be caught by the ticket validation process. + FAIL(FATAL_ERROR_INTERNAL); + // Update policy context + PolicyContextUpdate(commandCode, &in->authName, &in->policyRef, + &in->cpHashA, authTimeout, session); + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyTicket +#include "Tpm.h" +#include "PolicyOR_fp.h" +#if CC_PolicyOR // Conditional expansion of this file +#include "Policy_spt_fp.h" +TPM_RC +TPM2_PolicyOR( + PolicyOR_In *in // IN: input parameter list + ) +{ + SESSION *session; + UINT32 i; + // Input Validation and Update + // Get pointer to the session structure + session = SessionGet(in->policySession); + // Compare and Update Internal Session policy if match + for(i = 0; i < in->pHashList.count; i++) + { + if(session->attributes.isTrialPolicy == SET + || (MemoryEqual2B(&session->u2.policyDigest.b, + &in->pHashList.digests[i].b))) + { + // Found a match + HASH_STATE hashState; + TPM_CC commandCode = TPM_CC_PolicyOR; + // Start hash + session->u2.policyDigest.t.size + = CryptHashStart(&hashState, session->authHashAlg); + // Set policyDigest to 0 string and add it to hash + MemorySet(session->u2.policyDigest.t.buffer, 0, + session->u2.policyDigest.t.size); + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add command code + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // Add each of the hashes in the list + for(i = 0; i < in->pHashList.count; i++) + { + // Extend policyDigest + CryptDigestUpdate2B(&hashState, &in->pHashList.digests[i].b); + } + // Complete digest + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + return TPM_RC_SUCCESS; + } + } + // None of the values in the list matched the current policyDigest + return TPM_RCS_VALUE + RC_PolicyOR_pHashList; +} +#endif // CC_PolicyOR +#include "Tpm.h" +#include "PolicyPCR_fp.h" +#if CC_PolicyPCR // Conditional expansion of this file +/* TPM_RC_VALUE if provided, pcrDigest does not match the current PCR settings */ +/* TPM_RC_PCR_CHANGED a previous TPM2_PolicyPCR() set pcrCounter and it has changed */ +TPM_RC +TPM2_PolicyPCR( + PolicyPCR_In *in // IN: input parameter list + ) +{ + SESSION *session; + TPM2B_DIGEST pcrDigest; + BYTE pcrs[sizeof(TPML_PCR_SELECTION)]; + UINT32 pcrSize; + BYTE *buffer; + TPM_CC commandCode = TPM_CC_PolicyPCR; + HASH_STATE hashState; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + // Compute current PCR digest + PCRComputeCurrentDigest(session->authHashAlg, &in->pcrs, &pcrDigest); + // Do validation for non trial session + if(session->attributes.isTrialPolicy == CLEAR) + { + // Make sure that this is not going to invalidate a previous PCR check + if(session->pcrCounter != 0 && session->pcrCounter != gr.pcrCounter) + return TPM_RC_PCR_CHANGED; + // If the caller specified the PCR digest and it does not + // match the current PCR settings, return an error.. + if(in->pcrDigest.t.size != 0) + { + if(!MemoryEqual2B(&in->pcrDigest.b, &pcrDigest.b)) + return TPM_RCS_VALUE + RC_PolicyPCR_pcrDigest; + } + } + else + { + // For trial session, just use the input PCR digest if one provided + // Note: It can't be too big because it is a TPM2B_DIGEST and the size + // would have been checked during unmarshaling + if(in->pcrDigest.t.size != 0) + pcrDigest = in->pcrDigest; + } + // Internal Data Update + // Update policy hash + // policyDigestnew = hash( policyDigestold || TPM_CC_PolicyPCR + // || PCRS || pcrDigest) + // Start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // add PCRS + buffer = pcrs; + pcrSize = TPML_PCR_SELECTION_Marshal(&in->pcrs, &buffer, NULL); + CryptDigestUpdate(&hashState, pcrSize, pcrs); + // add PCR digest + CryptDigestUpdate2B(&hashState, &pcrDigest.b); + // complete the hash and get the results + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + // update pcrCounter in session context for non trial session + if(session->attributes.isTrialPolicy == CLEAR) + { + session->pcrCounter = gr.pcrCounter; + } + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyPCR +#include "Tpm.h" +#include "PolicyLocality_fp.h" +#if CC_PolicyLocality // Conditional expansion of this file +TPM_RC +TPM2_PolicyLocality( + PolicyLocality_In *in // IN: input parameter list + ) +{ + SESSION *session; + BYTE marshalBuffer[sizeof(TPMA_LOCALITY)]; + BYTE prevSetting[sizeof(TPMA_LOCALITY)]; + UINT32 marshalSize; + BYTE *buffer; + TPM_CC commandCode = TPM_CC_PolicyLocality; + HASH_STATE hashState; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + // Get new locality setting in canonical form + marshalBuffer[0] = 0; // Code analysis says that this is not initialized + buffer = marshalBuffer; + marshalSize = TPMA_LOCALITY_Marshal(&in->locality, &buffer, NULL); + // Its an error if the locality parameter is zero + if(marshalBuffer[0] == 0) + return TPM_RCS_RANGE + RC_PolicyLocality_locality; + // Get existing locality setting in canonical form + prevSetting[0] = 0; // Code analysis says that this is not initialized + buffer = prevSetting; + TPMA_LOCALITY_Marshal(&session->commandLocality, &buffer, NULL); + // If the locality has previously been set + if(prevSetting[0] != 0 + // then the current locality setting and the requested have to be the same + // type (that is, either both normal or both extended + && ((prevSetting[0] < 32) != (marshalBuffer[0] < 32))) + return TPM_RCS_RANGE + RC_PolicyLocality_locality; + // See if the input is a regular or extended locality + if(marshalBuffer[0] < 32) + { + // if there was no previous setting, start with all normal localities + // enabled + if(prevSetting[0] == 0) + prevSetting[0] = 0x1F; + // AND the new setting with the previous setting and store it in prevSetting + prevSetting[0] &= marshalBuffer[0]; + // The result setting can not be 0 + if(prevSetting[0] == 0) + return TPM_RCS_RANGE + RC_PolicyLocality_locality; + } + else + { + // for extended locality + // if the locality has already been set, then it must match the + if(prevSetting[0] != 0 && prevSetting[0] != marshalBuffer[0]) + return TPM_RCS_RANGE + RC_PolicyLocality_locality; + // Setting is OK + prevSetting[0] = marshalBuffer[0]; + } + // Internal Data Update + // Update policy hash + // policyDigestnew = hash(policyDigestold || TPM_CC_PolicyLocality || locality) + // Start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // add input locality + CryptDigestUpdate(&hashState, marshalSize, marshalBuffer); + // complete the digest + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + // update session locality by unmarshal function. The function must succeed + // because both input and existing locality setting have been validated. + buffer = prevSetting; + TPMA_LOCALITY_Unmarshal(&session->commandLocality, &buffer, + (INT32 *)&marshalSize); + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyLocality +#include "Tpm.h" +#include "PolicyNV_fp.h" +#if CC_PolicyNV // Conditional expansion of this file +#include "Policy_spt_fp.h" +TPM_RC +TPM2_PolicyNV( + PolicyNV_In *in // IN: input parameter list + ) +{ + TPM_RC result; + SESSION *session; + NV_REF locator; + NV_INDEX *nvIndex; + BYTE nvBuffer[sizeof(in->operandB.t.buffer)]; + TPM2B_NAME nvName; + TPM_CC commandCode = TPM_CC_PolicyNV; + HASH_STATE hashState; + TPM2B_DIGEST argHash; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + //If this is a trial policy, skip all validations and the operation + if(session->attributes.isTrialPolicy == CLEAR) + { + // No need to access the actual NV index information for a trial policy. + nvIndex = NvGetIndexInfo(in->nvIndex, &locator); + // Common read access checks. NvReadAccessChecks() may return + // TPM_RC_NV_AUTHORIZATION, TPM_RC_NV_LOCKED, or TPM_RC_NV_UNINITIALIZED + result = NvReadAccessChecks(in->authHandle, + in->nvIndex, + nvIndex->publicArea.attributes); + if(result != TPM_RC_SUCCESS) + return result; + // Make sure that offset is withing range + if(in->offset > nvIndex->publicArea.dataSize) + return TPM_RCS_VALUE + RC_PolicyNV_offset; + // Valid NV data size should not be smaller than input operandB size + if((nvIndex->publicArea.dataSize - in->offset) < in->operandB.t.size) + return TPM_RCS_SIZE + RC_PolicyNV_operandB; + // Get NV data. The size of NV data equals the input operand B size + NvGetIndexData(nvIndex, locator, in->offset, in->operandB.t.size, nvBuffer); + // Check to see if the condition is valid + if(!PolicySptCheckCondition(in->operation, nvBuffer, + in->operandB.t.buffer, in->operandB.t.size)) + return TPM_RC_POLICY; + } + // Internal Data Update + // Start argument hash + argHash.t.size = CryptHashStart(&hashState, session->authHashAlg); + // add operandB + CryptDigestUpdate2B(&hashState, &in->operandB.b); + // add offset + CryptDigestUpdateInt(&hashState, sizeof(UINT16), in->offset); + // add operation + CryptDigestUpdateInt(&hashState, sizeof(TPM_EO), in->operation); + // complete argument digest + CryptHashEnd2B(&hashState, &argHash.b); + // Update policyDigest + // Start digest + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // add argument digest + CryptDigestUpdate2B(&hashState, &argHash.b); + // Adding nvName + CryptDigestUpdate2B(&hashState, &EntityGetName(in->nvIndex, &nvName)->b); + // complete the digest + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyNV +#include "Tpm.h" +#include "PolicyCounterTimer_fp.h" +#if CC_PolicyCounterTimer // Conditional expansion of this file +#include "Policy_spt_fp.h" +TPM_RC +TPM2_PolicyCounterTimer( + PolicyCounterTimer_In *in // IN: input parameter list + ) +{ + SESSION *session; + TIME_INFO infoData; // data buffer of TPMS_TIME_INFO + BYTE *pInfoData = (BYTE *)&infoData; + UINT16 infoDataSize; + TPM_CC commandCode = TPM_CC_PolicyCounterTimer; + HASH_STATE hashState; + TPM2B_DIGEST argHash; + // Input Validation + // Get a marshaled time structure + infoDataSize = TimeGetMarshaled(&infoData); + pAssert(infoDataSize <= sizeof(infoData)); // libtpms added; 25 < 32 ==> unfounded coverity complaint + // Make sure that the referenced stays within the bounds of the structure. + // NOTE: the offset checks are made even for a trial policy because the policy + // will not make any sense if the references are out of bounds of the timer + // structure. + if(in->offset > infoDataSize) + return TPM_RCS_VALUE + RC_PolicyCounterTimer_offset; + if((UINT32)in->offset + (UINT32)in->operandB.t.size > infoDataSize) + return TPM_RCS_RANGE; + // Get pointer to the session structure + session = SessionGet(in->policySession); + //If this is a trial policy, skip the check to see if the condition is met. + if(session->attributes.isTrialPolicy == CLEAR) + { + // If the command is going to use any part of the counter or timer, need + // to verify that time is advancing. + // The time and clock vales are the first two 64-bit values in the clock + if(in->offset < sizeof(UINT64) + sizeof(UINT64)) + { + // Using Clock or Time so see if clock is running. Clock doesn't + // run while NV is unavailable. + // TPM_RC_NV_UNAVAILABLE or TPM_RC_NV_RATE error may be returned here. + RETURN_IF_NV_IS_NOT_AVAILABLE; + } + // offset to the starting position + pInfoData = (BYTE *)infoData; + // Check to see if the condition is valid + if(!PolicySptCheckCondition(in->operation, pInfoData + in->offset, + in->operandB.t.buffer, in->operandB.t.size)) + return TPM_RC_POLICY; + } + // Internal Data Update + // Start argument list hash + argHash.t.size = CryptHashStart(&hashState, session->authHashAlg); + // add operandB + CryptDigestUpdate2B(&hashState, &in->operandB.b); + // add offset + CryptDigestUpdateInt(&hashState, sizeof(UINT16), in->offset); + // add operation + CryptDigestUpdateInt(&hashState, sizeof(TPM_EO), in->operation); + // complete argument hash + CryptHashEnd2B(&hashState, &argHash.b); + // update policyDigest + // start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // add argument digest + CryptDigestUpdate2B(&hashState, &argHash.b); + // complete the digest + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyCounterTimer +#include "Tpm.h" +#include "PolicyCommandCode_fp.h" +#if CC_PolicyCommandCode // Conditional expansion of this file +/* Error Returns Meaning */ +/* TPM_RC_VALUE commandCode of policySession previously set to a different value */ +TPM_RC +TPM2_PolicyCommandCode( + PolicyCommandCode_In *in // IN: input parameter list + ) +{ + SESSION *session; + TPM_CC commandCode = TPM_CC_PolicyCommandCode; + HASH_STATE hashState; + // Input validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + if(session->commandCode != 0 && session->commandCode != in->code) + return TPM_RCS_VALUE + RC_PolicyCommandCode_code; + if(CommandCodeToCommandIndex(in->code) == UNIMPLEMENTED_COMMAND_INDEX) + return TPM_RCS_POLICY_CC + RC_PolicyCommandCode_code; + // Internal Data Update + // Update policy hash + // policyDigestnew = hash(policyDigestold || TPM_CC_PolicyCommandCode || code) + // Start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // add input commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), in->code); + // complete the hash and get the results + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + // update commandCode value in session context + session->commandCode = in->code; + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyCommandCode +#include "Tpm.h" +#include "PolicyPhysicalPresence_fp.h" +#if CC_PolicyPhysicalPresence // Conditional expansion of this file +TPM_RC +TPM2_PolicyPhysicalPresence( + PolicyPhysicalPresence_In *in // IN: input parameter list + ) +{ + SESSION *session; + TPM_CC commandCode = TPM_CC_PolicyPhysicalPresence; + HASH_STATE hashState; + // Internal Data Update + // Get pointer to the session structure + session = SessionGet(in->policySession); + // Update policy hash + // policyDigestnew = hash(policyDigestold || TPM_CC_PolicyPhysicalPresence) + // Start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // complete the digest + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + // update session attribute + session->attributes.isPPRequired = SET; + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyPhysicalPresence +#include "Tpm.h" +#include "PolicyCpHash_fp.h" +#if CC_PolicyCpHash // Conditional expansion of this file +TPM_RC +TPM2_PolicyCpHash( + PolicyCpHash_In *in // IN: input parameter list + ) +{ + SESSION *session; + TPM_CC commandCode = TPM_CC_PolicyCpHash; + HASH_STATE hashState; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + // A valid cpHash must have the same size as session hash digest + // NOTE: the size of the digest can't be zero because TPM_ALG_NULL + // can't be used for the authHashAlg. + if(in->cpHashA.t.size != CryptHashGetDigestSize(session->authHashAlg)) + return TPM_RCS_SIZE + RC_PolicyCpHash_cpHashA; + // error if the cpHash in session context is not empty and is not the same + // as the input or is not a cpHash + if((session->u1.cpHash.t.size != 0) + && (!session->attributes.isCpHashDefined + || !MemoryEqual2B(&in->cpHashA.b, &session->u1.cpHash.b))) + return TPM_RC_CPHASH; + // Internal Data Update + // Update policy hash + // policyDigestnew = hash(policyDigestold || TPM_CC_PolicyCpHash || cpHashA) + // Start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // add cpHashA + CryptDigestUpdate2B(&hashState, &in->cpHashA.b); + // complete the digest and get the results + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + // update cpHash in session context + session->u1.cpHash = in->cpHashA; + session->attributes.isCpHashDefined = SET; + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyCpHash +#include "Tpm.h" +#include "PolicyNameHash_fp.h" +#if CC_PolicyNameHash // Conditional expansion of this file +TPM_RC +TPM2_PolicyNameHash( + PolicyNameHash_In *in // IN: input parameter list + ) +{ + SESSION *session; + TPM_CC commandCode = TPM_CC_PolicyNameHash; + HASH_STATE hashState; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + // A valid nameHash must have the same size as session hash digest + // Since the authHashAlg for a session cannot be TPM_ALG_NULL, the digest size + // is always non-zero. + if(in->nameHash.t.size != CryptHashGetDigestSize(session->authHashAlg)) + return TPM_RCS_SIZE + RC_PolicyNameHash_nameHash; + // u1 in the policy session context cannot otherwise be occupied + if(session->u1.cpHash.b.size != 0 + || session->attributes.isBound + || session->attributes.isCpHashDefined + || session->attributes.isTemplateSet) + return TPM_RC_CPHASH; + // Internal Data Update + // Update policy hash + // policyDigestnew = hash(policyDigestold || TPM_CC_PolicyNameHash || nameHash) + // Start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // add nameHash + CryptDigestUpdate2B(&hashState, &in->nameHash.b); + // complete the digest + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + // update nameHash in session context + session->u1.cpHash = in->nameHash; + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyNameHash +#include "Tpm.h" +#include "PolicyDuplicationSelect_fp.h" +#if CC_PolicyDuplicationSelect // Conditional expansion of this file +TPM_RC +TPM2_PolicyDuplicationSelect( + PolicyDuplicationSelect_In *in // IN: input parameter list + ) +{ + SESSION *session; + HASH_STATE hashState; + TPM_CC commandCode = TPM_CC_PolicyDuplicationSelect; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + // cpHash in session context must be empty + if(session->u1.cpHash.t.size != 0) + return TPM_RC_CPHASH; + // commandCode in session context must be empty + if(session->commandCode != 0) + return TPM_RC_COMMAND_CODE; + // Internal Data Update + // Update name hash + session->u1.cpHash.t.size = CryptHashStart(&hashState, session->authHashAlg); + // add objectName + CryptDigestUpdate2B(&hashState, &in->objectName.b); + // add new parent name + CryptDigestUpdate2B(&hashState, &in->newParentName.b); + // complete hash + CryptHashEnd2B(&hashState, &session->u1.cpHash.b); + // update policy hash + // Old policyDigest size should be the same as the new policyDigest size since + // they are using the same hash algorithm + session->u2.policyDigest.t.size + = CryptHashStart(&hashState, session->authHashAlg); + // add old policy + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add command code + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // add objectName + if(in->includeObject == YES) + CryptDigestUpdate2B(&hashState, &in->objectName.b); + // add new parent name + CryptDigestUpdate2B(&hashState, &in->newParentName.b); + // add includeObject + CryptDigestUpdateInt(&hashState, sizeof(TPMI_YES_NO), in->includeObject); + // complete digest + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + // set commandCode in session context + session->commandCode = TPM_CC_Duplicate; + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyDuplicationSelect +#include "Tpm.h" +#include "PolicyAuthorize_fp.h" +#if CC_PolicyAuthorize // Conditional expansion of this file +#include "Policy_spt_fp.h" +TPM_RC +TPM2_PolicyAuthorize( + PolicyAuthorize_In *in // IN: input parameter list + ) +{ + SESSION *session; + TPM2B_DIGEST authHash; + HASH_STATE hashState; + TPMT_TK_VERIFIED ticket; + TPM_ALG_ID hashAlg; + UINT16 digestSize; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + // Extract from the Name of the key, the algorithm used to compute it's Name + hashAlg = BYTE_ARRAY_TO_UINT16(in->keySign.t.name); + // 'keySign' parameter needs to use a supported hash algorithm, otherwise + // can't tell how large the digest should be + if(!CryptHashIsValidAlg(hashAlg, FALSE)) + return TPM_RCS_HASH + RC_PolicyAuthorize_keySign; + digestSize = CryptHashGetDigestSize(hashAlg); + if(digestSize != (in->keySign.t.size - 2)) + return TPM_RCS_SIZE + RC_PolicyAuthorize_keySign; + //If this is a trial policy, skip all validations + if(session->attributes.isTrialPolicy == CLEAR) + { + // Check that "approvedPolicy" matches the current value of the + // policyDigest in policy session + if(!MemoryEqual2B(&session->u2.policyDigest.b, + &in->approvedPolicy.b)) + return TPM_RCS_VALUE + RC_PolicyAuthorize_approvedPolicy; + // Validate ticket TPMT_TK_VERIFIED + // Compute aHash. The authorizing object sign a digest + // aHash := hash(approvedPolicy || policyRef). + // Start hash + authHash.t.size = CryptHashStart(&hashState, hashAlg); + // add approvedPolicy + CryptDigestUpdate2B(&hashState, &in->approvedPolicy.b); + // add policyRef + CryptDigestUpdate2B(&hashState, &in->policyRef.b); + // complete hash + CryptHashEnd2B(&hashState, &authHash.b); + // re-compute TPMT_TK_VERIFIED + TicketComputeVerified(in->checkTicket.hierarchy, &authHash, + &in->keySign, &ticket); + // Compare ticket digest. If not match, return error + if(!MemoryEqual2B(&in->checkTicket.digest.b, &ticket.digest.b)) + return TPM_RCS_VALUE + RC_PolicyAuthorize_checkTicket; + } + // Internal Data Update + // Set policyDigest to zero digest + PolicyDigestClear(session); + // Update policyDigest + PolicyContextUpdate(TPM_CC_PolicyAuthorize, &in->keySign, &in->policyRef, + NULL, 0, session); + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyAuthorize +#include "Tpm.h" +#include "PolicyAuthValue_fp.h" +#if CC_PolicyAuthValue // Conditional expansion of this file +#include "Policy_spt_fp.h" +TPM_RC +TPM2_PolicyAuthValue( + PolicyAuthValue_In *in // IN: input parameter list + ) +{ + SESSION *session; + TPM_CC commandCode = TPM_CC_PolicyAuthValue; + HASH_STATE hashState; + // Internal Data Update + // Get pointer to the session structure + session = SessionGet(in->policySession); + // Update policy hash + // policyDigestnew = hash(policyDigestold || TPM_CC_PolicyAuthValue) + // Start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // complete the hash and get the results + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + // update isAuthValueNeeded bit in the session context + session->attributes.isAuthValueNeeded = SET; + session->attributes.isPasswordNeeded = CLEAR; + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyAuthValue +#include "Tpm.h" +#include "PolicyPassword_fp.h" +#if CC_PolicyPassword // Conditional expansion of this file +#include "Policy_spt_fp.h" +TPM_RC +TPM2_PolicyPassword( + PolicyPassword_In *in // IN: input parameter list + ) +{ + SESSION *session; + TPM_CC commandCode = TPM_CC_PolicyAuthValue; + HASH_STATE hashState; + // Internal Data Update + // Get pointer to the session structure + session = SessionGet(in->policySession); + // Update policy hash + // policyDigestnew = hash(policyDigestold || TPM_CC_PolicyAuthValue) + // Start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // complete the digest + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + // Update isPasswordNeeded bit + session->attributes.isPasswordNeeded = SET; + session->attributes.isAuthValueNeeded = CLEAR; + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyPassword +#include "Tpm.h" +#include "PolicyGetDigest_fp.h" +#if CC_PolicyGetDigest // Conditional expansion of this file +TPM_RC +TPM2_PolicyGetDigest( + PolicyGetDigest_In *in, // IN: input parameter list + PolicyGetDigest_Out *out // OUT: output parameter list + ) +{ + SESSION *session; + // Command Output + // Get pointer to the session structure + session = SessionGet(in->policySession); + out->policyDigest = session->u2.policyDigest; + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyGetDigest +#include "Tpm.h" +#include "PolicyNvWritten_fp.h" +#if CC_PolicyNvWritten // Conditional expansion of this file +TPM_RC +TPM2_PolicyNvWritten( + PolicyNvWritten_In *in // IN: input parameter list + ) +{ + SESSION *session; + TPM_CC commandCode = TPM_CC_PolicyNvWritten; + HASH_STATE hashState; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + // If already set is this a duplicate (the same setting)? If it + // is a conflicting setting, it is an error + if(session->attributes.checkNvWritten == SET) + { + if(((session->attributes.nvWrittenState == SET) + != (in->writtenSet == YES))) + return TPM_RCS_VALUE + RC_PolicyNvWritten_writtenSet; + } + // Internal Data Update + // Set session attributes so that the NV Index needs to be checked + session->attributes.checkNvWritten = SET; + session->attributes.nvWrittenState = (in->writtenSet == YES); + // Update policy hash + // policyDigestnew = hash(policyDigestold || TPM_CC_PolicyNvWritten + // || writtenSet) + // Start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // add the byte of writtenState + CryptDigestUpdateInt(&hashState, sizeof(TPMI_YES_NO), in->writtenSet); + // complete the digest + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyNvWritten +#include "Tpm.h" +#include "PolicyTemplate_fp.h" +#if CC_PolicyTemplate // Conditional expansion of this file +TPM_RC +TPM2_PolicyTemplate( + PolicyTemplate_In *in // IN: input parameter list + ) +{ + SESSION *session; + TPM_CC commandCode = TPM_CC_PolicyTemplate; + HASH_STATE hashState; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + // If the template is set, make sure that it is the same as the input value + if(session->attributes.isTemplateSet) + { + if(!MemoryEqual2B(&in->templateHash.b, &session->u1.cpHash.b)) + return TPM_RCS_VALUE + RC_PolicyTemplate_templateHash; + } + // error if cpHash contains something that is not a template + else if(session->u1.templateHash.t.size != 0) + return TPM_RC_CPHASH; + // A valid templateHash must have the same size as session hash digest + if(in->templateHash.t.size != CryptHashGetDigestSize(session->authHashAlg)) + return TPM_RCS_SIZE + RC_PolicyTemplate_templateHash; + // Internal Data Update + // Update policy hash + // policyDigestnew = hash(policyDigestold || TPM_CC_PolicyCpHash + // || cpHashA.buffer) + // Start hash + CryptHashStart(&hashState, session->authHashAlg); + // add old digest + CryptDigestUpdate2B(&hashState, &session->u2.policyDigest.b); + // add commandCode + CryptDigestUpdateInt(&hashState, sizeof(TPM_CC), commandCode); + // add cpHashA + CryptDigestUpdate2B(&hashState, &in->templateHash.b); + // complete the digest and get the results + CryptHashEnd2B(&hashState, &session->u2.policyDigest.b); + // update cpHash in session context + session->u1.templateHash = in->templateHash; + session->attributes.isTemplateSet = SET; + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyTemplateHash +#include "Tpm.h" +#if CC_PolicyAuthorizeNV // Conditional expansion of this file +#include "PolicyAuthorizeNV_fp.h" +#include "Policy_spt_fp.h" +TPM_RC +TPM2_PolicyAuthorizeNV( + PolicyAuthorizeNV_In *in + ) +{ + SESSION *session; + TPM_RC result; + NV_REF locator; + NV_INDEX *nvIndex = NvGetIndexInfo(in->nvIndex, &locator); + TPM2B_NAME name; + TPMT_HA policyInNv; + BYTE nvTemp[sizeof(TPMT_HA)]; + BYTE *buffer = nvTemp; + INT32 size; + // Input Validation + // Get pointer to the session structure + session = SessionGet(in->policySession); + // Skip checks if this is a trial policy + if(!session->attributes.isTrialPolicy) + { + // Check the authorizations for reading + // Common read access checks. NvReadAccessChecks() returns + // TPM_RC_NV_AUTHORIZATION, TPM_RC_NV_LOCKED, or TPM_RC_NV_UNINITIALIZED + // error may be returned at this point + result = NvReadAccessChecks(in->authHandle, in->nvIndex, + nvIndex->publicArea.attributes); + if(result != TPM_RC_SUCCESS) + return result; + // Read the contents of the index into a temp buffer + size = MIN(nvIndex->publicArea.dataSize, sizeof(TPMT_HA)); + NvGetIndexData(nvIndex, locator, 0, (UINT16)size, nvTemp); + // Unmarshal the contents of the buffer into the internal format of a + // TPMT_HA so that the hash and digest elements can be accessed from the + // structure rather than the byte array that is in the Index (written by + // user of the Index). + result = TPMT_HA_Unmarshal(&policyInNv, &buffer, &size, FALSE); + if(result != TPM_RC_SUCCESS) + return result; + // Verify that the hash is the same + if(policyInNv.hashAlg != session->authHashAlg) + return TPM_RC_HASH; + // See if the contents of the digest in the Index matches the value + // in the policy + if(!MemoryEqual(&policyInNv.digest, &session->u2.policyDigest.t.buffer, + session->u2.policyDigest.t.size)) + return TPM_RC_VALUE; + } + // Internal Data Update + // Set policyDigest to zero digest + PolicyDigestClear(session); + // Update policyDigest + PolicyContextUpdate(TPM_CC_PolicyAuthorizeNV, EntityGetName(in->nvIndex, &name), + NULL, NULL, 0, session); + return TPM_RC_SUCCESS; +} +#endif // CC_PolicyAuthorizeNV |