ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/obm/Common/SecureBoot/Security.c b/marvell/obm/Common/SecureBoot/Security.c
new file mode 100644
index 0000000..73b47b5
--- /dev/null
+++ b/marvell/obm/Common/SecureBoot/Security.c
@@ -0,0 +1,814 @@
+/****************************************************************************
+ *
+ *  (C)Copyright 2005 - 2010 Marvell. All Rights Reserved.
+ *
+ *  THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF MARVELL.
+ *  The copyright notice above does not evidence any actual or intended
+ *  publication of such source code. This Module contains Proprietary
+ *  Information of Marvell and should be treated as Confidential. The
+ *  information in this file is provided for the exclusive use of the
+ *  licensees of Marvell. Such users have the right to use, modify, and
+ *  incorporate this code into products for purposes authorized by the
+ *  license agreement provided they include this notice and the associated
+ *  copyright notice with any such product.
+ *
+ *  The information in this file is provided "AS IS" without warranty.
+ *
+ ***************************************************************************/
+
+#include "Security.h"
+#include "tim.h"
+#include "misc.h"
+#include "PlatformConfig.h"
+
+#if USE_WTM3_TBR
+	#include "WTM3_TBR_Lib.h"
+	//#include "WTM3_TBR_Interrupts.h"
+	#include "self_test_vectors.h"
+#elif BL_USE_WTM_CRYPTO
+	#include "WTM3_MBOX_Interface.h"
+#elif ( USE_IPPCP_LIB || BL_USE_SECURITY_CALLBACK )
+	#include "crypt_lib.h"
+#endif
+
+#if ( USE_IPPCP_LIB || BL_USE_SECURITY_CALLBACK )
+#if (AARCH64)
+__align(8)
+#endif
+	// Passed in data buffer to replace the IPPCP Read/Write space in the library. 
+#if ( ECDSA_SUPPORTED ) 
+	UINT8_T pECDSA_DataBuffer[10540]={0};	// For ECDSA - KeyBitLen=521
+#else
+	UINT8_T* pECDSA_DataBuffer = NULL;
+#endif
+#else
+	UINT8_T* pECDSA_DataBuffer = NULL;	// Used mainly for building non-IPPCP platforms.
+#endif
+
+
+// Generic pointers to security functions dynamically bound based on underlying security architecture.
+static SECURITY_FUNCTIONS SFs;
+
+pSECURITY_FUNCTIONS GetSecurityFunctionsPointer()
+{
+    return &SFs;
+}
+
+UINT8_T* GetECDSADataBufferPointer()
+{
+	return pECDSA_DataBuffer;
+}
+
+static UINT_T (*P_SHAMessageDigest) (const UINT8_T* pSrcMesgIn, UINT_T SrcMesgByteLen, \
+									UINT8_T* pMesgDigestOut, UINT_T DigestByteLen) = NULL;
+
+static UINT_T (*P_PKCS_DSA_Verify) (const UINT8_T* pSrcMesgIn, UINT_T SrcMesgByteLen, \
+									const pPLAT_DS pDSA, UINT8_T* DataBuffer) = NULL;	
+
+static UINT_T SHAMessageDigest(const UINT8_T* pSrcMesgIn, UINT_T SrcMesgByteLen, \
+								UINT8_T* pMesgDigestOut, UINT_T DigestByteLen)
+{
+#if LAPW && !CP_BOOT
+	if(PlatformIsLapwB0() && HwHashIsUsed()) {
+		dcache_clean_range(pSrcMesgIn, SrcMesgByteLen);
+		dcache_clean_invalidate_range(pMesgDigestOut, DigestByteLen);
+	}
+#endif
+
+	if (!P_SHAMessageDigest)
+		return SecurityFunctionNotSupported;
+
+	return P_SHAMessageDigest(pSrcMesgIn, SrcMesgByteLen, pMesgDigestOut, DigestByteLen);
+}
+
+static UINT_T PKCS_DSA_Verify(const UINT8_T* pSrcMesgIn, UINT_T SrcMesgByteLen, \
+								const pPLAT_DS pDSA, UINT8_T* DataBuffer)
+{
+#if LAPW && !CP_BOOT
+	if(PlatformIsLapwB0() && HwHashIsUsed()) {
+		dcache_clean_range(pSrcMesgIn, SrcMesgByteLen);
+		dcache_clean_invalidate_range(DataBuffer, DATABUFFERSIZE);
+	}
+#endif
+
+	if (!P_PKCS_DSA_Verify)
+		return SecurityFunctionNotSupported;
+
+	return P_PKCS_DSA_Verify(pSrcMesgIn, SrcMesgByteLen, pDSA, DataBuffer);
+}
+
+/********************	SecurityInitialization ***************************************
+*	 This routine is in charge of doing any security Initialization needed
+********************************************************************************************/
+UINT_T SecurityInitialization(UINT_T ver_adv)
+{
+ 	UINT_T Retval = NoError;
+
+#if USE_WTM3_TBR
+	//WTM3_TBR_Enable_AES_Interrupts();
+	SFs.pInitializeSecurity		= &WTM3_TBR_SecurityInitialization;
+	SFs.pSHAMessageDigest		= &WTM3_TBR_SHAMessageDigest;
+	SFs.pPKCS_DSA_Verify		= &WTM3_TBR_PKCS_DSA_Verify;
+  #if ECDSA_SUPPORTED
+	SFs.pECCP_DSA_Verify		= &WTM3_TBR_ECCP_DSA_Verify;
+  #else
+	SFs.pECCP_DSA_Verify		= NULL;
+  #endif
+	SFs.pGet_NonceBitLen		= &WTM3_TBR_Get_NonceBitLen;
+	SFs.pGet_Nonce				= &WTM3_TBR_Get_Nonce;
+	SFs.pAES_Decrypt			= &WTM3_TBR_AES_DECRYPT;
+	SFs.pAES_Encrypt			= &WTM3_TBR_AES_ENCRYPT;
+	SFs.pHMAC					= NULL;
+#elif BL_USE_WTM_CRYPTO
+	
+	SFs.pInitializeSecurity		= &WTM3_MBOX_SecurityInitialization;
+	SFs.pSHAMessageDigest		= &WTM3_MBOX_SHAMessageDigest;
+	SFs.pPKCS_DSA_Verify		= &WTM3_MBOX_PKCS_DSA_Verify;
+#if ECDSA_SUPPORTED
+	SFs.pECCP_DSA_Verify		= &WTM3_MBOX_ECCP_DSA_Verify;
+#else
+	SFs.pECCP_DSA_Verify		= NULL;
+#endif
+	SFs.pGet_NonceBitLen		= NULL;	// This maybe implemented in future 
+	SFs.pGet_Nonce				= NULL;	// This is supported by WTM Kernel (WTM_DRBG_GEN_RAN_BITS), maybe implemented in future
+	SFs.pAES_Decrypt			= &WTM3_MBOX_AES_Decrypt;
+	SFs.pAES_Encrypt			= &WTM3_MBOX_AES_Encrypt;
+	SFs.pHMAC					= NULL;
+#elif USE_IPPCP_LIB
+	SFs.pInitializeSecurity		= &IPPCP_SecurityInitialization;
+	SFs.pSHAMessageDigest		= &IPPCP_SHAMessageDigest;
+	SFs.pPKCS_DSA_Verify		= &IPPCP_PKCS_DSA_Verify;
+#if ECDSA_SUPPORTED
+#if ENABLE_NEON	 
+	SFs.pECCP_DSA_Verify		= &IPPCP_ECCP_DSA_Verify;
+#else
+	SFs.pECCP_DSA_Verify		= NULL;
+#endif
+#endif
+	SFs.pGet_NonceBitLen		= IPPCP_Get_NonceBitLen;
+	SFs.pGet_Nonce				= IPPCP_Get_Nonce;
+	SFs.pAES_Decrypt			= NULL;
+	SFs.pAES_Encrypt			= NULL;
+	SFs.pHMAC					= NULL;
+#elif BL_USE_SECURITY_CALLBACK
+	SetSecurityCallBackFunctionPointers();	// Sets the SFs function pointers with supported call back functions
+											// This needs to be a platform specific call as different ROMs
+											// support different security functions.
+#endif
+
+	P_SHAMessageDigest = SFs.pSHAMessageDigest;
+	SFs.pSHAMessageDigest = &SHAMessageDigest;
+
+	P_PKCS_DSA_Verify = SFs.pPKCS_DSA_Verify;
+	SFs.pPKCS_DSA_Verify = &PKCS_DSA_Verify;
+		 	
+ 	Retval = SFs.pInitializeSecurity(ver_adv);
+ 	return Retval;
+}
+
+/******************** SecurityShutdown*********************************************************
+* This routine should do Security Driver related cleanup and hardware shutdown 
+************************************************************************************************/
+
+UINT_T SecurityShutdown()
+{
+	UINT_T Retval = NoError;
+#if BL_USE_WTM_CRYPTO	
+	Retval = WTM3_MBOX_SecurityShutdown();
+#endif
+	return Retval;
+}
+
+/********************	ValidateTIMSignature ******************************************************
+*  Validate the TIM structure 
+*    It is assumed that the TIM structure has already been loaded with a call to LoadTIM()
+*	  in flash.c
+*
+********************************************************************************************/
+UINT_T ValidateTIMSignature(pTIM pTIM_h)
+{
+	UINT_T Retval = NoError;
+	CHAR *Buffer = NULL, *AlignedBuffer;
+
+	switch (pTIM_h->pTBTIM_DS->DSAlgorithmID)
+	{
+		case PKCS1_v1_5_Ippcp:
+#if ECDSA_SUPPORTED
+		case ECDSA_256:
+		case ECDSA_521:
+#endif
+		case PKCS1_v2_2_Ippcp:
+			break;
+		default:
+			return InvalidSecureBootMethodError;
+	}
+
+	if ((pTIM_h->pTBTIM_DS->DSAlgorithmID == PKCS1_v1_5_Ippcp) || (pTIM_h->pTBTIM_DS->DSAlgorithmID == PKCS1_v2_2_Ippcp))
+	{
+		if (SFs.pPKCS_DSA_Verify != NULL)	// Verify signature if this function is supported
+		{
+			if ( pTIM_h->pTBTIM_DS->HashAlgorithmID == SHA512)	// SHA512 is not supported with PKCS
+			{
+				return SecurityFunctionNotSupported;
+			}
+			Buffer = malloc(ALIGN_UP(DATABUFFERSIZE, DCACHE_LINE_SIZE));
+			if (Buffer) {
+				AlignedBuffer = ALIGN_UP((UINT_T)Buffer, DCACHE_LINE_SIZE);
+	 			Retval = SFs.pPKCS_DSA_Verify( (UINT8_T*) pTIM_h->pConsTIM, pTIM_h->pImg[0].ImageSizeToHash, pTIM_h->pTBTIM_DS, AlignedBuffer);
+				free(Buffer);
+			} else{
+				return HeapExhaustedError;
+			}
+		}
+		else	// Else, return not supported error
+		{
+			return SecurityFunctionNotSupported;
+		}		
+	}
+#if ECDSA_SUPPORTED
+	else if ((pTIM_h->pTBTIM_DS->DSAlgorithmID == ECDSA_256) || (pTIM_h->pTBTIM_DS->DSAlgorithmID == ECDSA_521))
+	{
+		if (SFs.pECCP_DSA_Verify != NULL)	// Verify signature if this function is supported
+		{
+	 		Retval = SFs.pECCP_DSA_Verify( (UINT8_T*) pTIM_h->pConsTIM, pTIM_h->pImg[0].ImageSizeToHash, pTIM_h->pTBTIM_DS, pECDSA_DataBuffer);
+		}
+		else	// Else, return not supported error
+		{
+			return SecurityFunctionNotSupported;
+		}
+	}
+#endif
+	else { 
+		return InvalidDSAError;
+	}
+	
+	if (Retval != NoError)
+		return InvalidTIMImageError; 
+ 	
+ 	return NoError;
+}
+
+/********************	VerifySignature ******************************************************
+*  Verify the DSA for any signature
+********************************************************************************************/
+UINT_T VerifySignature(const UINT8_T* pBufferToVerifyIn, UINT_T NumBytesToVerify, const UINT_T* pSignatureIn, const pKEY_MOD_3_4_0 pKeyIn, UINT_T ReverseSignatureBytes)
+{
+	UINT_T Retval = NoError;
+	//UINT_T KeyByteLen = (pKeyIn->KeySize +7)>>3;
+	UINT_T KeySizeInWords = (pKeyIn->KeySize==521) ? 17 : pKeyIn->KeySize/32;
+	PLAT_DS Signature;
+	CHAR *Buffer = NULL, *AlignedBuffer;
+	UINT_T i;
+	const pPLAT_DS pSignature = & Signature;
+
+	/* abandoned, ReverseSignatureBytes is always 0 in OBM
+	if(ReverseSignatureBytes) {
+		ReverseBytes((UINT8_T *)pSignatureIn, KeyByteLen);	//reverse bytes for signature
+	}
+	*/
+
+	Signature.DSAlgorithmID = pKeyIn->EncryptAlgorithmID;
+	Signature.KeySize = pKeyIn->KeySize;
+	Signature.HashAlgorithmID = pKeyIn->HashAlgorithmID;
+
+	if ((pKeyIn->EncryptAlgorithmID == PKCS1_v1_5_Ippcp) || (pKeyIn->EncryptAlgorithmID == PKCS1_v2_2_Ippcp))
+	{
+		if (SFs.pPKCS_DSA_Verify != NULL)	// Verify signature if this function is supported
+		{
+			for (i=0; i < KeySizeInWords; i++)
+			{
+				Signature.Rsa.RSAModulus[i] = pKeyIn->Rsa.RSAModulus[i];
+				Signature.Rsa.RSAPublicExponent[i] = pKeyIn->Rsa.RSAPublicExponent[i];
+				Signature.Rsa.RSADigS[i] = pSignatureIn[i];
+			}
+			Buffer = malloc(ALIGN_UP(DATABUFFERSIZE, DCACHE_LINE_SIZE));
+			if (Buffer) {
+ 				AlignedBuffer = ALIGN_UP((UINT_T)Buffer, DCACHE_LINE_SIZE);
+ 				Retval = SFs.pPKCS_DSA_Verify(pBufferToVerifyIn, NumBytesToVerify, pSignature, AlignedBuffer);
+				free(Buffer);
+			} else {
+				return HeapExhaustedError;
+			}
+		}
+		else	// Else, return not supported error
+		{
+			return SecurityFunctionNotSupported;
+		}		
+	}
+#if ECDSA_SUPPORTED
+	else if ((pKeyIn->EncryptAlgorithmID == ECDSA_256) || (pKeyIn->EncryptAlgorithmID == ECDSA_521)) 
+	{
+		if (SFs.pECCP_DSA_Verify != NULL)	// Verify signature if this function is supported
+		{
+			for (i=0; i < KeySizeInWords; i++)
+			{
+				Signature.Ecdsa.ECDSAPublicKeyCompX[i] = pKeyIn->Ecdsa.PublicKeyCompX[i];
+				Signature.Ecdsa.ECDSAPublicKeyCompY[i] = pKeyIn->Ecdsa.PublicKeyCompY[i];
+				Signature.Ecdsa.ECDSADigS_R[i] = pSignatureIn[i];
+				Signature.Ecdsa.ECDSADigS_S[i] = pSignatureIn[MAXECCKEYSIZEWORDS+i];
+			}
+ 			Retval = SFs.pECCP_DSA_Verify(pBufferToVerifyIn, NumBytesToVerify, pSignature, pECDSA_DataBuffer);
+		}
+		else	// Else, return not supported error
+		{
+			return SecurityFunctionNotSupported;
+		}
+	}
+#endif
+	else { 
+		return InvalidDSAError;
+	}  
+
+    return Retval;
+}
+
+
+/********************	ValidateImage ******************************************************
+*  Validate the Image based on a Hash passed in for the TIM or the hash for individual images
+*  can be determined from IMAGE_INFO structure.
+*
+********************************************************************************************/
+UINT_T ValidateImage(UINT_T ImageAddr, UINT_T ImageID, pTIM pTIM_h)
+{
+	UINT_T Retval = NoError;
+	UINT_T HashSize = 0;
+	UINT_T i, ImageSize, HashAlgorithmID;
+	UINT_T *Buffer = NULL;
+	UINT_T *CalculatedHash;//Contains 16 32-bit words
+	UINT_T HashInTIM[WordLengthOf_SHA512];				// Contains 16 32-bit words
+	UINT_T ImageType;
+
+
+	pIMAGE_INFO_3_4_0 pImageInfo = NULL;
+	pImageInfo = FindImageInTIM(pTIM_h, ImageID);
+	if (pImageInfo == NULL)
+		return NoError; // return no error if not tim included
+
+	// If (TRUSTED TIM) or (TRUSTED FUSE BIT is set)
+	if (pTIM_h->pConsTIM->VersionBind.Trusted)
+	{
+		// If we are trying to Validate the TIM, it requires checking the DS. Special method to do that.
+		if ((pImageInfo->ImageID == TIMIDENTIFIER) ||  (pImageInfo->ImageID == NONTZDTIMID) )
+		{
+			Retval = ValidateTIMSignature(pTIM_h);
+			if (Retval != NoError)
+				return InvalidTIMImageError;
+			else
+				return Retval;
+	 	}
+	}
+
+	// First get relavant image data.
+	ImageSize = pImageInfo->ImageSize;	
+	HashSize  = pImageInfo->ImageSizeToHash;
+	HashAlgorithmID = pImageInfo->HashAlgorithmID; 
+
+	// Make sure we got an expected HashAlgorithmID
+	switch (HashAlgorithmID)
+	{
+		case SHA160:
+		case SHA256:
+		case SHA512:
+			break;
+		default:
+			return InvalidSecureBootMethodError;
+	}
+
+	ImageType = pImageInfo->PartitionNumber.bits.ImageType;
+
+	switch(ImageType) {
+	case DLCMD_LZMA_IMAGE_TYPE:
+	case DLCMD_LZMA2_IMAGE_TYPE:
+	case DLCMD_YAFFS_LZMA_IMAGE_TYPE:
+	case DLCMD_UBIFS_LZMA_IMAGE_TYPE:
+	case DLCMD_JFFS2_LZMA_IMAGE_TYPE:
+	case DLCMD_RAW_LZMA_IMAGE_TYPE:
+	case DLCMD_IMG_LZMA_IMAGE_TYPE:
+	case DLCMD_IMG_MXZ_IMAGE_TYPE:
+		break;
+	default:
+		if(ImageSize < HashSize)
+			return (HashSizeMismatch);
+	}
+
+	if( HashSize == 0 ) 
+		return NoError;
+
+	// Read the image hash into a local variable.
+	for (i = 0; i < (HashAlgorithmID / 4); i++)
+	{
+		HashInTIM[i] = pImageInfo->Hash[i];			// Save the actual hash value
+	}
+
+	// If the image that will be validated is the TIM itself, we
+	// need to sample the TIM.bin hash out of the TIM image struct
+	// and fill it with zeroes so that we can compute the correct
+	// hash again.
+	if ( (pImageInfo->ImageID == TIMIDENTIFIER)  || (pImageInfo->ImageID == NONTZDTIMID) )
+	{
+		for (i = 0; i < (HashAlgorithmID / 4); i++)
+		{
+			pImageInfo->Hash[i] = 0x0; 				// Overwrite the actual hash value with zeroes.
+		}
+	}
+
+	Buffer = malloc(ALIGN_UP((WordLengthOf_SHA256 << 2), DCACHE_LINE_SIZE));
+	if (Buffer == NULL) {
+		return HeapExhaustedError;
+	}
+	CalculatedHash = ALIGN_UP((UINT_T)Buffer, DCACHE_LINE_SIZE);
+
+	// If HASHing is supported, compute the hash
+	if (SFs.pSHAMessageDigest != NULL)
+	{
+		Retval = SFs.pSHAMessageDigest((UINT8_T*)ImageAddr, HashSize, (UINT8_T*) CalculatedHash, (HASHALGORITHMID_T) HashAlgorithmID);
+	}
+	else	// Else, return not supported error
+	{
+		free(Buffer);
+		return SecurityFunctionNotSupported;
+	}
+
+	// Write back the hash value to the hash field of the TIM image.
+	if ( (pImageInfo->ImageID == TIMIDENTIFIER)  || (pImageInfo->ImageID == NONTZDTIMID) )
+	{
+		for (i = 0; i < (HashAlgorithmID / 4); i++)
+		{
+			pImageInfo->Hash[i] = HashInTIM[i]; 	// Write the hash values back.
+		}
+	}
+
+	// Check the return value coming from the SHAMessageDigest function.
+	// If there is an error, return with this error code.
+	if (Retval != NoError) {
+		free(Buffer);
+		return Retval;
+	}
+
+	// Compare the 2 hashes
+	for (i = 0; i < (HashAlgorithmID / 4); i++)
+	{
+		if (HashInTIM[i] != CalculatedHash[i]) {
+			free(Buffer);
+			return (InvalidImageHash);
+		}
+	}
+
+	free(Buffer);
+ 	return Retval;
+}
+
+UINT_T ValidateImageSDTim(UINT_T ImageAddr, UINT_T ImageID, pTIM pDTIM, pTIM pTIM_h)
+{
+#ifdef CONFIG_ASR_SDTIM
+	UINT_T Retval = NoError;
+	pTIM pSDTIM_h = NULL;
+	pIMAGE_INFO_3_4_0 pImageInfo = NULL;
+	pIMAGE_INFO_3_4_0 pSdtimInfo = NULL;
+	UINT_T SecCfg = 0;
+
+	pImageInfo = FindImageInTIM(pDTIM, ImageID);
+	if (pImageInfo == NULL)
+		return NoError; // return no error if not tim included
+
+	if(!ImageIsSDTIMIncluded(pImageInfo))
+		return ValidateImage(ImageAddr, ImageID, pDTIM);
+
+	pSDTIM_h = malloc(sizeof(TIM));
+	if(pSDTIM_h == NULL)
+		return HeapExhaustedError;
+
+	Retval = SetTIMPointers(ImageAddr, pSDTIM_h);
+	if(Retval) {
+		free(pSDTIM_h);
+		return InvalidTIMImageError;
+	}
+
+	pSdtimInfo = FindImageInTIM(pSDTIM_h, SDTIM);
+	if(pSdtimInfo == NULL) {
+		free(pSDTIM_h);
+		return TIMNotFound;
+	}
+
+	SecCfg = GetSDTimSecureConfig(pSdtimInfo);
+	if(SecCfg == 0) {
+		free(pSDTIM_h);
+		return NoError;
+	}
+
+	Retval = ValiateDTIM(pSDTIM_h, pTIM_h);
+	if(Retval != NoError) {
+		free(pSDTIM_h);
+		return Retval;
+	}
+
+	ImageAddr += GetSDTimSpaceSize(pSdtimInfo);
+	Retval = ValidateImage(ImageAddr, ImageID, pSDTIM_h);
+	free(pSDTIM_h);
+
+	return Retval;
+#else
+	(VOID)pTIM_h;
+	return ValidateImage(ImageAddr, ImageID, pDTIM);
+#endif
+}
+
+#if TRUSTED
+/******************** VerifyPlatformKey *********************************************************
+* 	Verify that the hash of the keys stored in this Digital Signature match what's burned on the processor
+************************************************************************************************/
+UINT_T VerifyPlatformKey (pTIM pTIM_h)
+{
+	UINT_T Retval = NoError;
+	UINT_T FusedOEMKeyHash[WordLengthOf_SHA256];
+	UINT_T zero[WordLengthOf_SHA256];
+	UINT_T HashDataSizeInBytes, KeySizeInWords;
+	UINT_T KeyData[BINDKEYSIZE] = {0};
+	CHAR *Buffer = NULL;
+	UINT_T *CalculatedHash;			// Contains 8 words
+	UINT_T	i;
+
+	memset(zero, 0, ByteLengthOf_SHA256); //clear out 32 bytes
+
+	// Read out the fuse hashes
+	Retval = ReadOemHashKeyFuseBits(FusedOEMKeyHash, ByteLengthOf_SHA256 );
+	if (Retval != NoError)
+		 return Retval;
+
+	if (memcmp(zero, FusedOEMKeyHash, ByteLengthOf_SHA256) == 0) // No OEM key Hash is burnt, just return NoError
+		return NoError;
+	
+	switch (pTIM_h->pTBTIM_DS->DSAlgorithmID)
+	{
+		case PKCS1_v1_5_Ippcp:
+#if ECDSA_SUPPORTED
+		case ECDSA_256:
+		case ECDSA_521:
+#endif
+		case PKCS1_v2_2_Ippcp:
+			break;
+		default:
+			return InvalidSecureBootMethodError;
+	} 
+
+	switch (pTIM_h->pTBTIM_DS->HashAlgorithmID)
+	{
+		case SHA160:
+		case SHA256:
+		case SHA512:
+			break;
+		default:
+			return InvalidSecureBootMethodError;
+	} 
+
+	KeySizeInWords = (pTIM_h->pTBTIM_DS->KeySize==521)?17:pTIM_h->pTBTIM_DS->KeySize/32; // Convert Bits to Words
+	
+	if (pTIM_h->pConsTIM->VersionBind.Version >= (TIM_3_4_00))
+		HashDataSizeInBytes = (KeySizeInWords*2 + 1) * 4;	// (crypto_scheme||modulus-or-X||exponent-or-Y) in bytes (*4)
+	else
+		HashDataSizeInBytes = KeySizeInWords *4*2;			// (exponent-or-X||modulus-or-Y) in bytes (*4)	
+
+		
+	// If LONG_KEYS == 1, hash algorithm has to be SHA512
+	//if ( (pFuses->bits.LongKeys == LONGKEYSENABLED) && (pTIM_h->pTBTIM_DS->HashAlgorithmID != SHA512) )
+	//	return InvalidKeyHashError;
+			
+
+	// Prepare the KeyData to calculate Hash of the Keys
+	if ((pTIM_h->pTBTIM_DS->DSAlgorithmID == PKCS1_v1_5_Ippcp) || (pTIM_h->pTBTIM_DS->DSAlgorithmID == PKCS1_v2_2_Ippcp))
+	{
+
+		if (pTIM_h->pConsTIM->VersionBind.Version >= (TIM_3_4_00)) {
+
+			// 1) Pack the crypto_scheme
+			//crypto_scheme:	0x0000A100	PKCSv1_SHA1_1024RSA  
+			//					0x0000A110	PKCSv1_SHA256_1024RSA
+			//					0x0000A200	PKCSv1_SHA1_2048RSA  
+			//					0x0000A210	PKCSv1_SHA256_2048RSA
+			//					0x0000A300	PKCSv1_PSS_SHA1_1024RSA  
+			//					0x0000A310	PKCSv1_PSS_SHA256_1024RSA
+			//					0x0000A400	PKCSv1_PSS_SHA1_2048RSA  
+			//					0x0000A410	PKCSv1_PSS_SHA256_2048RSA
+			if(pTIM_h->pTBTIM_DS->HashAlgorithmID == SHA256)
+			{
+				if (pTIM_h->pTBTIM_DS->DSAlgorithmID == PKCS1_v1_5_Ippcp)
+					KeyData[0] = (KeySizeInWords == 64) ? PKCSv1_SHA256_2048RSA : PKCSv1_SHA256_1024RSA;
+				else if (pTIM_h->pTBTIM_DS->DSAlgorithmID == PKCS1_v2_2_Ippcp)
+					KeyData[0] = (KeySizeInWords == 64) ? PKCSv1_PSS_SHA256_2048RSA : PKCSv1_PSS_SHA256_1024RSA;
+			}
+			else	 // Defaults to 160
+			{
+				if (pTIM_h->pTBTIM_DS->DSAlgorithmID == PKCS1_v1_5_Ippcp)
+					KeyData[0] = (KeySizeInWords == 64) ? PKCSv1_SHA1_2048RSA : PKCSv1_SHA1_1024RSA;
+				else if (pTIM_h->pTBTIM_DS->DSAlgorithmID == PKCS1_v2_2_Ippcp)
+					KeyData[0] = (KeySizeInWords == 64) ? PKCSv1_PSS_SHA1_2048RSA : PKCSv1_PSS_SHA1_1024RSA;
+			}
+
+			// 2) Pack the Modulus and Exponent
+			for (i=0; i < KeySizeInWords; i++)
+			{
+				KeyData[i+1] = pTIM_h->pTBTIM_DS->Rsa.RSAModulus[i];
+				KeyData[i+KeySizeInWords+1] = pTIM_h->pTBTIM_DS->Rsa.RSAPublicExponent[i];
+			}
+		}
+		else {	// DO NOT include crypto_scheme and DO NOT swap exponent and modulus !!!
+			// Pack the Exponent and Modulus
+			for (i=0; i < KeySizeInWords; i++)
+			{
+				KeyData[i] = pTIM_h->pTBTIM_DS->Rsa.RSAPublicExponent[i];
+				KeyData[i+KeySizeInWords] = pTIM_h->pTBTIM_DS->Rsa.RSAModulus[i];
+			}
+		}
+	}
+#if ECDSA_SUPPORTED
+	else // ECDSA
+	{
+		if (pTIM_h->pConsTIM->VersionBind.Version >= (TIM_3_4_00)) {
+		    // 1) Pack the crypto_scheme
+			//crypto_scheme:	0x0000B101	ECCP256_FIPS_DSA_SHA1  
+			//					0x0000B111	ECCP256_FIPS_DSA_SHA256
+			//					0x0000B141	ECCP256_FIPS_DSA_SHA512  
+			//					0x0000B301	ECCP521_FIPS_DSA_SHA1  
+			//					0x0000B311	ECCP521_FIPS_DSA_SHA256
+			//					0x0000B341	ECCP521_FIPS_DSA_SHA512
+			if(pTIM_h->pTBTIM_DS->HashAlgorithmID == SHA512)
+				KeyData[0] = (KeySizeInWords == 17) ? ECCP521_FIPS_DSA_SHA512 : ECCP256_FIPS_DSA_SHA512;				
+			else if(pTIM_h->pTBTIM_DS->HashAlgorithmID == SHA256)
+				KeyData[0] = (KeySizeInWords == 17) ? ECCP521_FIPS_DSA_SHA256 : ECCP256_FIPS_DSA_SHA256;
+			else	 // Defaults to 160
+				KeyData[0] = (KeySizeInWords == 17) ? ECCP521_FIPS_DSA_SHA1 : ECCP256_FIPS_DSA_SHA1;
+			
+			// 2) Pack the X-coordinate and Y-coordinate
+			for (i=0; i < KeySizeInWords; i++)
+			{
+				KeyData[i+1] = pTIM_h->pTBTIM_DS->Ecdsa.ECDSAPublicKeyCompX[i]; 
+				KeyData[i+KeySizeInWords+1] = pTIM_h->pTBTIM_DS->Ecdsa.ECDSAPublicKeyCompY[i];
+			}
+		}
+		else {	// DO NOT include crypto_scheme !!!
+			// Pack the X-coordinate and Y-coordinate
+			for (i=0; i < KeySizeInWords; i++)
+			{
+				KeyData[i] = pTIM_h->pTBTIM_DS->Ecdsa.ECDSAPublicKeyCompX[i]; 
+				KeyData[i+KeySizeInWords] = pTIM_h->pTBTIM_DS->Ecdsa.ECDSAPublicKeyCompY[i];
+			}
+		}
+	}
+#endif
+
+	//Key Padding is on by default
+	HashDataSizeInBytes = BINDKEYSIZE*4; // MaxKeySize*2+CryptoScheme in Bytes: 129*4 = 516
+
+	Buffer = malloc(ALIGN_UP((WordLengthOf_SHA256 << 2), DCACHE_LINE_SIZE));
+	if (Buffer == NULL) {
+		return HeapExhaustedError;
+	}
+	CalculatedHash = ALIGN_UP((UINT_T)Buffer, DCACHE_LINE_SIZE);
+
+	// Do the SHA Hash				
+	Retval =  SFs.pSHAMessageDigest((unsigned char *)KeyData, HashDataSizeInBytes,
+									(unsigned char *)CalculatedHash, 
+									(HASHALGORITHMID_T) pTIM_h->pTBTIM_DS->HashAlgorithmID);
+										
+	if (Retval != NoError){
+		free(Buffer);
+		return Retval;
+	}
+
+	// Compare Hash of the Keys from the TIM vs. what's stored in the fuses.
+	for (i = 0; i < (pTIM_h->pTBTIM_DS->HashAlgorithmID / 4); i++)
+	{
+		if (CalculatedHash[i] != FusedOEMKeyHash[i]) {
+			free(Buffer);
+			return (InvalidOTPHashError);
+		}
+	}
+	
+	free(Buffer);
+	return Retval;
+}
+
+/********************	ValidateKeyHashes ******************************************************
+*  Validate the Keys based on a OTP Hash passed or from the Hash stored in TIM
+*	If the OEM keys are being verified (TIMIDENTIFIER) do the platform verify PI as well
+********************************************************************************************/
+UINT_T VerifyKey(KEYMODULES_T KeyType, pTIM pTIM_h)
+{
+	UINT_T Retval = NoError;
+	
+	// Check if we are to Perform Platform Verification.
+	if (KeyType == PlatformVerificationKey)
+		Retval = VerifyPlatformKey(pTIM_h);
+
+	// TBD Add support to verify other keys as well as needed.
+
+	return Retval;
+}
+
+/********************	CalcBufferHash ******************************************************
+*  Calc the Hash of Input Buffer, Not Useds
+********************************************************************************************/
+INT_T CalcBufferHash(UINT_T *Buffer, UINT_T NumBytesToHash, UINT_T *HashBuff, HASHALGORITHMID_T HashType)
+{
+	UINT_T Retval = NoError;
+	switch (HashType)
+	{
+		case SHA160:
+		case SHA256:
+		case SHA512:
+			break;
+		default:
+			return InvalidSecureBootMethodError;
+	}
+	Retval = SFs.pSHAMessageDigest((UINT8_T*)Buffer, NumBytesToHash, (UINT8_T*) HashBuff, HashType);			
+
+	return Retval;
+}
+
+/********************	VerifyBufferHash ******************************************************
+*  Verify the Hash of Input Buffer, Not Used
+********************************************************************************************/
+UINT_T VerifyBufferHash(UINT_T BufferAddr, UINT_T NumBytesToVerify, HASHALGORITHMID_T HashType, const UINT_T * pHashValueIn)
+{
+	UINT_T Retval, i;
+	UINT_T CalculatedHash[WordLengthOf_SHA512];			// Contains 16 32-bit words
+
+	if( NumBytesToVerify == 0 ) 
+		return NoError;
+
+	switch (HashType)
+	{
+		case SHA160:
+		case SHA256:
+		case SHA512:
+			break;
+		default:
+			return InvalidSecureBootMethodError;
+	} 
+
+
+	// Compute the hash
+	Retval = SFs.pSHAMessageDigest((UINT8_T*)BufferAddr, NumBytesToVerify, (UINT8_T*) CalculatedHash, HashType);			
+
+	// Check the return value coming from the SHAMessageDigest function.
+	// If there is an error, return with this error code.
+	if (Retval != NoError)
+		return Retval;
+
+	// Compare the 2 hashes
+	for (i = 0; i < (HashType / 4); i++)
+	{
+		if (pHashValueIn[i] != CalculatedHash[i])
+			return (InvalidImageHash);
+	}
+
+ 	return NoError;
+}
+    
+#endif //BOOTROM
+
+
+#if !BOOTROM	// BootLoader Only
+/******************** VerifyEncryptedKey ***************************************************
+*  Verify the Signature of Encrypted Key
+********************************************************************************************/
+UINT_T VerifyEncryptedKey(pKEY_MOD_3_4_0 PlainTextKey, pKEY_MOD_3_4_0 EncryptedKey, pKEY_MOD_3_4_0 DecryptionKey)
+{		
+	UINT_T Retval = NoError; 
+ 
+	if ((DecryptionKey->EncryptAlgorithmID == PKCS1_v1_5_Ippcp) || (DecryptionKey->EncryptAlgorithmID == PKCS1_v2_2_Ippcp))
+	{
+		// First verify the signature of the public exponent 	
+		Retval = VerifySignature((UINT8_T*) PlainTextKey->Rsa.RSAPublicExponent, (PlainTextKey->KeySize)/8, (UINT_T*) EncryptedKey->EncryptedRsa.EncryptedHashRSAPublicExponent, DecryptionKey, 0);
+		if (Retval != NoError)	// Signature of the exponent is NOT valid
+		{
+			return Retval;
+		}
+		else					// Signature of the exponent is valid
+		{
+			// Verify the signature of the public modulus 	
+			Retval = VerifySignature((UINT8_T*) PlainTextKey->Rsa.RSAModulus, (PlainTextKey->KeySize)/8, (UINT_T*) EncryptedKey->EncryptedRsa.EncryptedHashRSAModulus, DecryptionKey, 0);
+		}
+	}
+#if ECDSA_SUPPORTED
+	else if ((DecryptionKey->EncryptAlgorithmID == ECDSA_256) || (DecryptionKey->EncryptAlgorithmID == ECDSA_521))
+	{
+		// First verify the signature of the X component 	
+		Retval = VerifySignature((UINT8_T*) PlainTextKey->Ecdsa.PublicKeyCompX, ((PlainTextKey->KeySize+31)/32)*4, (UINT_T*) EncryptedKey->EncryptedEcdsa.EncryptedHashPublicKeyCompX_R, DecryptionKey, 0);
+		if (Retval != NoError)	// Signature of the X component is NOT valid
+		{
+			return Retval;
+		}
+		else					// Signature of the X component is valid
+		{
+			// Verify the signature of the Y component 	
+			Retval = VerifySignature((UINT8_T*) PlainTextKey->Ecdsa.PublicKeyCompY, ((PlainTextKey->KeySize+31)/32)*4, (UINT_T*) EncryptedKey->EncryptedEcdsa.EncryptedHashPublicKeyCompY_R, DecryptionKey, 0);
+		}
+	}
+#endif
+	else
+		return InvalidEncAlgorithmID; 
+	return Retval;
+}
+
+#endif	// #if !BOOTROM