/** @file
Implement TPM2 help.
Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
typedef struct {
TPMI_ALG_HASH HashAlgo;
UINT16 HashSize;
UINT32 HashMask;
} INTERNAL_HASH_INFO;
STATIC INTERNAL_HASH_INFO mHashInfo[] = {
{TPM_ALG_SHA1, SHA1_DIGEST_SIZE, HASH_ALG_SHA1},
{TPM_ALG_SHA256, SHA256_DIGEST_SIZE, HASH_ALG_SHA256},
{TPM_ALG_SM3_256, SM3_256_DIGEST_SIZE, HASH_ALG_SM3_256},
{TPM_ALG_SHA384, SHA384_DIGEST_SIZE, HASH_ALG_SHA384},
{TPM_ALG_SHA512, SHA512_DIGEST_SIZE, HASH_ALG_SHA512},
};
/**
Return size of digest.
@param[in] HashAlgo Hash algorithm
@return size of digest
**/
UINT16
EFIAPI
GetHashSizeFromAlgo (
IN TPMI_ALG_HASH HashAlgo
)
{
UINTN Index;
for (Index = 0; Index < sizeof(mHashInfo)/sizeof(mHashInfo[0]); Index++) {
if (mHashInfo[Index].HashAlgo == HashAlgo) {
return mHashInfo[Index].HashSize;
}
}
return 0;
}
/**
Get hash mask from algorithm.
@param[in] HashAlgo Hash algorithm
@return Hash mask
**/
UINT32
EFIAPI
GetHashMaskFromAlgo (
IN TPMI_ALG_HASH HashAlgo
)
{
UINTN Index;
for (Index = 0; Index < sizeof(mHashInfo)/sizeof(mHashInfo[0]); Index++) {
if (mHashInfo[Index].HashAlgo == HashAlgo) {
return mHashInfo[Index].HashMask;
}
}
return 0;
}
/**
Copy AuthSessionIn to TPM2 command buffer.
@param [in] AuthSessionIn Input AuthSession data
@param [out] AuthSessionOut Output AuthSession data in TPM2 command buffer
@return AuthSession size
**/
UINT32
EFIAPI
CopyAuthSessionCommand (
IN TPMS_AUTH_COMMAND *AuthSessionIn, OPTIONAL
OUT UINT8 *AuthSessionOut
)
{
UINT8 *Buffer;
Buffer = (UINT8 *)AuthSessionOut;
//
// Add in Auth session
//
if (AuthSessionIn != NULL) {
// sessionHandle
WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(AuthSessionIn->sessionHandle));
Buffer += sizeof(UINT32);
// nonce
WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (AuthSessionIn->nonce.size));
Buffer += sizeof(UINT16);
CopyMem (Buffer, AuthSessionIn->nonce.buffer, AuthSessionIn->nonce.size);
Buffer += AuthSessionIn->nonce.size;
// sessionAttributes
*(UINT8 *)Buffer = *(UINT8 *)&AuthSessionIn->sessionAttributes;
Buffer++;
// hmac
WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16 (AuthSessionIn->hmac.size));
Buffer += sizeof(UINT16);
CopyMem (Buffer, AuthSessionIn->hmac.buffer, AuthSessionIn->hmac.size);
Buffer += AuthSessionIn->hmac.size;
} else {
// sessionHandle
WriteUnaligned32 ((UINT32 *)Buffer, SwapBytes32(TPM_RS_PW));
Buffer += sizeof(UINT32);
// nonce = nullNonce
WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0));
Buffer += sizeof(UINT16);
// sessionAttributes = 0
*(UINT8 *)Buffer = 0x00;
Buffer++;
// hmac = nullAuth
WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0));
Buffer += sizeof(UINT16);
}
return (UINT32)((UINTN)Buffer - (UINTN)AuthSessionOut);
}
/**
Copy AuthSessionIn from TPM2 response buffer.
@param [in] AuthSessionIn Input AuthSession data in TPM2 response buffer
@param [out] AuthSessionOut Output AuthSession data
@return 0 copy failed
else AuthSession size
**/
UINT32
EFIAPI
CopyAuthSessionResponse (
IN UINT8 *AuthSessionIn,
OUT TPMS_AUTH_RESPONSE *AuthSessionOut OPTIONAL
)
{
UINT8 *Buffer;
TPMS_AUTH_RESPONSE LocalAuthSessionOut;
if (AuthSessionOut == NULL) {
AuthSessionOut = &LocalAuthSessionOut;
}
Buffer = (UINT8 *)AuthSessionIn;
// nonce
AuthSessionOut->nonce.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
Buffer += sizeof(UINT16);
if (AuthSessionOut->nonce.size > sizeof(TPMU_HA)) {
DEBUG ((DEBUG_ERROR, "CopyAuthSessionResponse - nonce.size error %x\n", AuthSessionOut->nonce.size));
return 0;
}
CopyMem (AuthSessionOut->nonce.buffer, Buffer, AuthSessionOut->nonce.size);
Buffer += AuthSessionOut->nonce.size;
// sessionAttributes
*(UINT8 *)&AuthSessionOut->sessionAttributes = *(UINT8 *)Buffer;
Buffer++;
// hmac
AuthSessionOut->hmac.size = SwapBytes16 (ReadUnaligned16 ((UINT16 *)Buffer));
Buffer += sizeof(UINT16);
if (AuthSessionOut->hmac.size > sizeof(TPMU_HA)) {
DEBUG ((DEBUG_ERROR, "CopyAuthSessionResponse - hmac.size error %x\n", AuthSessionOut->hmac.size));
return 0;
}
CopyMem (AuthSessionOut->hmac.buffer, Buffer, AuthSessionOut->hmac.size);
Buffer += AuthSessionOut->hmac.size;
return (UINT32)((UINTN)Buffer - (UINTN)AuthSessionIn);
}
/**
Return if hash alg is supported in HashAlgorithmMask.
@param HashAlg Hash algorithm to be checked.
@param HashAlgorithmMask Bitfield of allowed hash algorithms.
@retval TRUE Hash algorithm is supported.
@retval FALSE Hash algorithm is not supported.
**/
BOOLEAN
EFIAPI
IsHashAlgSupportedInHashAlgorithmMask(
IN TPMI_ALG_HASH HashAlg,
IN UINT32 HashAlgorithmMask
)
{
switch (HashAlg) {
case TPM_ALG_SHA1:
if ((HashAlgorithmMask & HASH_ALG_SHA1) != 0) {
return TRUE;
}
break;
case TPM_ALG_SHA256:
if ((HashAlgorithmMask & HASH_ALG_SHA256) != 0) {
return TRUE;
}
break;
case TPM_ALG_SHA384:
if ((HashAlgorithmMask & HASH_ALG_SHA384) != 0) {
return TRUE;
}
break;
case TPM_ALG_SHA512:
if ((HashAlgorithmMask & HASH_ALG_SHA512) != 0) {
return TRUE;
}
break;
case TPM_ALG_SM3_256:
if ((HashAlgorithmMask & HASH_ALG_SM3_256) != 0) {
return TRUE;
}
break;
}
return FALSE;
}
/**
Copy TPML_DIGEST_VALUES into a buffer
@param[in,out] Buffer Buffer to hold copied TPML_DIGEST_VALUES compact binary.
@param[in] DigestList TPML_DIGEST_VALUES to be copied.
@param[in] HashAlgorithmMask HASH bits corresponding to the desired digests to copy.
@return The end of buffer to hold TPML_DIGEST_VALUES.
**/
VOID *
EFIAPI
CopyDigestListToBuffer (
IN OUT VOID *Buffer,
IN TPML_DIGEST_VALUES *DigestList,
IN UINT32 HashAlgorithmMask
)
{
UINTN Index;
UINT16 DigestSize;
UINT32 DigestListCount;
UINT32 *DigestListCountPtr;
DigestListCountPtr = (UINT32 *) Buffer;
DigestListCount = 0;
Buffer = (UINT8 *)Buffer + sizeof(DigestList->count);
for (Index = 0; Index < DigestList->count; Index++) {
if (!IsHashAlgSupportedInHashAlgorithmMask(DigestList->digests[Index].hashAlg, HashAlgorithmMask)) {
DEBUG ((EFI_D_ERROR, "WARNING: TPM2 Event log has HashAlg unsupported by PCR bank (0x%x)\n", DigestList->digests[Index].hashAlg));
continue;
}
CopyMem (Buffer, &DigestList->digests[Index].hashAlg, sizeof(DigestList->digests[Index].hashAlg));
Buffer = (UINT8 *)Buffer + sizeof(DigestList->digests[Index].hashAlg);
DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);
CopyMem (Buffer, &DigestList->digests[Index].digest, DigestSize);
Buffer = (UINT8 *)Buffer + DigestSize;
DigestListCount++;
}
WriteUnaligned32 (DigestListCountPtr, DigestListCount);
return Buffer;
}
/**
Get TPML_DIGEST_VALUES data size.
@param[in] DigestList TPML_DIGEST_VALUES data.
@return TPML_DIGEST_VALUES data size.
**/
UINT32
EFIAPI
GetDigestListSize (
IN TPML_DIGEST_VALUES *DigestList
)
{
UINTN Index;
UINT16 DigestSize;
UINT32 TotalSize;
TotalSize = sizeof(DigestList->count);
for (Index = 0; Index < DigestList->count; Index++) {
DigestSize = GetHashSizeFromAlgo (DigestList->digests[Index].hashAlg);
TotalSize += sizeof(DigestList->digests[Index].hashAlg) + DigestSize;
}
return TotalSize;
}
/**
This function get digest from digest list.
@param[in] HashAlg Digest algorithm
@param[in] DigestList Digest list
@param[out] Digest Digest
@retval EFI_SUCCESS Digest is found and returned.
@retval EFI_NOT_FOUND Digest is not found.
**/
EFI_STATUS
EFIAPI
GetDigestFromDigestList (
IN TPMI_ALG_HASH HashAlg,
IN TPML_DIGEST_VALUES *DigestList,
OUT VOID *Digest
)
{
UINTN Index;
UINT16 DigestSize;
DigestSize = GetHashSizeFromAlgo (HashAlg);
for (Index = 0; Index < DigestList->count; Index++) {
if (DigestList->digests[Index].hashAlg == HashAlg) {
CopyMem (
Digest,
&DigestList->digests[Index].digest,
DigestSize
);
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}