| /**************************************************************************** |
| * |
| * (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 |