#include <common.h> | |
#include <malloc.h> | |
#include "obm2osl.h" | |
#include "tim.h" | |
#include "cmdline.h" | |
#include <asm/cache.h> | |
#include <asm/arch/cpu.h> | |
#define DATABUFFERSIZE (0x2000) | |
#define BR_SCB_Addr (0xFFE00040) | |
#define SCB_InitializeSecurity_Addr (BR_SCB_Addr + 0x0) | |
#define SCB_SHAMessageDigest_Addr (BR_SCB_Addr + 0x4) | |
#define SCB_PKCS_DSA_Verify_Addr (BR_SCB_Addr + 0x8) | |
#define SCB_ECCP_DSA_Verify_Addr (BR_SCB_Addr + 0xC) | |
#define SCB_Get_Nonce_Addr (BR_SCB_Addr + 0x10) | |
#define SCB_Get_NonceBitLen_Addr (BR_SCB_Addr + 0x14) | |
#define SCB_HMAC_KEY_GEN_Addr (BR_SCB_Addr + 0x18) | |
#define SCB_HMAC_Addr (BR_SCB_Addr + 0x1C) | |
typedef struct | |
{ | |
unsigned int (*pinit_security) (unsigned int ver_adv); | |
unsigned int (*psha) (const unsigned char* src, unsigned int src_len, unsigned char* hash, unsigned int hash_len); | |
unsigned int (*ppkcs_rsa_veriry)(const unsigned char* src, unsigned int src_len, const pPLAT_DS pdsa, unsigned char* buffer); | |
unsigned int (*peccp_rsa_verify)(const unsigned char* src, unsigned int src_len, const pPLAT_DS pdsa, unsigned char* buffer); | |
unsigned int (*pget_nonce_bit_len) (void); | |
unsigned int (*pget_nonce) (unsigned int* nonce, unsigned int bitlen); | |
unsigned int (*paes_decrpt) (unsigned int scheme_enum, void *source, void *dest, unsigned int data_len, void *key, void *iv); | |
unsigned int (*paes_encrpt) (unsigned int scheme_enum, void *source, void *dest, unsigned int data_len, void *key, void *iv); | |
unsigned int (*phmac) ( const unsigned char* phmac_key, const unsigned char* src, unsigned int src_len, unsigned char* dig_out ); | |
} SecureAPIs, *pSecureAPIs; | |
static SecureAPIs asrSecFuncs = { | |
.pinit_security = NULL, | |
.psha = SCB_SHAMessageDigest_Addr, | |
.ppkcs_rsa_veriry = SCB_PKCS_DSA_Verify_Addr, | |
.peccp_rsa_verify = NULL, | |
.pget_nonce_bit_len = NULL, | |
.pget_nonce = NULL, | |
.paes_encrpt = NULL, | |
.paes_decrpt = NULL, | |
.phmac = NULL, | |
}; | |
static pSecureAPIs pSA = &asrSecFuncs; | |
/* | |
* only RSA2048 is supported for now | |
*/ | |
int asr_rsa_verify(const unsigned char* src, unsigned int len, | |
const unsigned int* sig, const unsigned char *key) | |
{ | |
unsigned int ret, i; | |
PLAT_DS Signature; | |
const pPLAT_DS pSignature = &Signature; | |
unsigned int keysize_in_word; | |
unsigned char *buffer = NULL; | |
pKEY_MOD_3_4_0 pKeyIn = (pKEY_MOD_3_4_0)key; | |
Signature.DSAlgorithmID = pKeyIn->EncryptAlgorithmID; | |
Signature.KeySize = pKeyIn->KeySize; | |
Signature.HashAlgorithmID = pKeyIn->HashAlgorithmID; | |
keysize_in_word = (pKeyIn->KeySize==521) ? 17 : pKeyIn->KeySize/32; | |
if (pKeyIn->EncryptAlgorithmID == PKCS1_v1_5_Ippcp) { | |
if (pSA->ppkcs_rsa_veriry != NULL) { | |
buffer = memalign(CONFIG_SYS_CACHELINE_SIZE, DATABUFFERSIZE); | |
if (buffer == NULL) | |
return -1; | |
for (i = 0; i < keysize_in_word; i++) { | |
Signature.Rsa.RSAModulus[i] = pKeyIn->Rsa.RSAModulus[i]; | |
Signature.Rsa.RSAPublicExponent[i] = pKeyIn->Rsa.RSAPublicExponent[i]; | |
Signature.Rsa.RSADigS[i] = sig[i]; | |
} | |
if(cpu_is_asr1903_b0()) { | |
flush_dcache_range(src, (u32)src + len); | |
flush_dcache_range(pSignature, (u32)pSignature + MAXRSAKEYSIZEWORDS * 12); | |
invalidate_dcache_range(buffer, (u32)buffer + DATABUFFERSIZE); | |
} | |
ret = pSA->ppkcs_rsa_veriry(src, len, pSignature, buffer); | |
free(buffer); | |
return ret; | |
} | |
} | |
return -1; | |
} | |
int verify_tim_signature(pTIM pTIM_h) | |
{ | |
int ret = 0; | |
struct IMAGE_INFO_3_4_0 *pImg = NULL; | |
unsigned char *buffer = NULL; | |
if (pTIM_h->ctim->version_bind.trusted == 0) | |
return 0; | |
if (pTIM_h->tbtim_ds->DSAlgorithmID != PKCS1_v1_5_Ippcp) | |
return -1; | |
if (pSA->ppkcs_rsa_veriry != NULL) { | |
buffer = memalign(CONFIG_SYS_CACHELINE_SIZE, DATABUFFERSIZE); | |
if (buffer == NULL) | |
return -1; | |
pImg = (struct IMAGE_INFO_3_4_0 *)pTIM_h->img; | |
if(cpu_is_asr1903_b0()) { | |
flush_dcache_range(pTIM_h->ctim, (u32)pTIM_h->ctim + pImg[0].image_size_to_hash); | |
flush_dcache_range(pTIM_h->tbtim_ds, (u32)pTIM_h->tbtim_ds + (MAXRSAKEYSIZEWORDS * 12)); | |
invalidate_dcache_range(buffer, (buffer) + DATABUFFERSIZE); | |
} | |
ret = pSA->ppkcs_rsa_veriry(pTIM_h->ctim, pImg[0].image_size_to_hash, | |
pTIM_h->tbtim_ds, buffer); | |
free(buffer); | |
return ret; | |
} | |
return -1; | |
} | |
static int verify_dtim_key(pKEY_MOD_3_4_0 PlainTextKey, | |
pKEY_MOD_3_4_0 EncryptedKey, pKEY_MOD_3_4_0 DecryptionKey) | |
{ | |
int ret = 0; | |
int keysize = 0; | |
if (DecryptionKey->EncryptAlgorithmID == PKCS1_v1_5_Ippcp) | |
{ | |
keysize = (PlainTextKey->KeySize)/8; | |
// First verify the signature of the public exponent | |
ret = asr_rsa_verify((unsigned char*)PlainTextKey->Rsa.RSAPublicExponent, keysize, | |
(unsigned int*) EncryptedKey->EncryptedRsa.EncryptedHashRSAPublicExponent, DecryptionKey); | |
if (ret == 0) // Signature of the exponent is NOT valid | |
{ | |
// Verify the signature of the public modulus | |
ret = asr_rsa_verify((unsigned char*) PlainTextKey->Rsa.RSAModulus, keysize, | |
(unsigned int*) EncryptedKey->EncryptedRsa.EncryptedHashRSAModulus, DecryptionKey); | |
} | |
return ret; | |
} | |
return ret; | |
} | |
int verify_dtim(pTIM pDTIM_h, pTIM pTIM_h) | |
{ | |
unsigned int Retval = NoError; | |
unsigned int PlainTextKeyPacked[MAXRSAKEYSIZEWORDS * 2]; | |
unsigned int PlainTextKeyLength; | |
pKEY_MOD_3_4_0 pEncryptedKey = NULL; | |
pKEY_MOD_3_4_0 pDecryptionKey = NULL; | |
pKEY_MOD_3_4_0 pPlainTextKey = NULL; | |
if( pDTIM_h->ctim->version_bind.trusted ) | |
{ | |
// Prepare the ENCRYPTED KEY | |
// pEncryptedKey has the encrypted key now | |
pEncryptedKey = FindKeyInTIM(pDTIM_h, ENCK); | |
// If key not found, return with this error | |
if (pEncryptedKey == NULL) | |
{ | |
return -1; | |
} | |
pDecryptionKey = (KEY_MOD_3_4_0 *)malloc(DDR_DECRYPTIONKEY_LEN); | |
pPlainTextKey = (KEY_MOD_3_4_0 *)malloc(DDR_PLAINTEXTKEY_LEN); | |
if(pDecryptionKey == NULL || pPlainTextKey == NULL) { | |
return -1; | |
} | |
memset(pDecryptionKey, 0, sizeof(KEY_MOD_3_4_0)); | |
memset(pPlainTextKey, 0, sizeof(KEY_MOD_3_4_0)); | |
// Prepare the DECRYPTION KEY | |
// Setup the key structure that will be used to decrypt the public | |
// key hash associated with DTIM. In this case, this key is the | |
// public key that is used in the initial TIM. The algorithm and | |
// key size information is imported from the encrypted key. | |
pDecryptionKey->HashAlgorithmID = pEncryptedKey->HashAlgorithmID; | |
pDecryptionKey->KeySize = pEncryptedKey->KeySize; | |
pDecryptionKey->EncryptAlgorithmID = (pEncryptedKey->EncryptAlgorithmID) & 0x7FFFFFFF; | |
// Since the keys are represented as a union, the following will | |
// work for ECC as well. | |
memcpy(pDecryptionKey->Rsa.RSAPublicExponent, pTIM_h->tbtim_ds->Rsa.RSAPublicExponent, MAXRSAKEYSIZEWORDS*4); | |
memcpy(pDecryptionKey->Rsa.RSAModulus, pTIM_h->tbtim_ds->Rsa.RSAModulus, MAXRSAKEYSIZEWORDS*4); | |
// Prepare the PLAINTEXT KEY | |
pPlainTextKey->KeySize = pDTIM_h->tbtim_ds->KeySize; | |
// Plain text key that is signed is essentially the public key of the DTIM. | |
// Read the public key components into the PlainTextKey structure. | |
// Note that since the keys are represented as a union, the following will | |
// work for ECC as well. | |
memcpy(pPlainTextKey->Rsa.RSAPublicExponent, pDTIM_h->tbtim_ds->Rsa.RSAPublicExponent, MAXRSAKEYSIZEWORDS*4); | |
memcpy(pPlainTextKey->Rsa.RSAModulus, pDTIM_h->tbtim_ds->Rsa.RSAModulus, MAXRSAKEYSIZEWORDS*4); | |
// Before we validate the TIM, make sure its public key is correct | |
// by comparing it against its encrypted hash. | |
Retval = verify_dtim_key(pPlainTextKey, pEncryptedKey, pDecryptionKey); | |
free(pDecryptionKey); | |
free(pPlainTextKey); | |
if (Retval != NoError) | |
{ | |
printf("Verify Encrypted Key Failed: 0x%x\n\r", Retval); | |
return -1; | |
} | |
} | |
// Validate the DTIM. | |
Retval = verify_tim_signature(pDTIM_h); | |
if (Retval != NoError) | |
{ | |
printf("Verify DTIM Signature Failed: 0x%x\n\r", Retval); | |
return -1; | |
} | |
return 0; | |
} |