blob: d97c1e0faf4c33b9d789a05a252e932ca8974aa4 [file] [log] [blame]
#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;
}