blob: 63d6f6936442b8288cca14c26e8ac1bf9261f7b9 [file] [log] [blame]
/****************************************************************************
*
* (C)Copyright 2015 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 "GEU_Provisioning.h"
#include "Security.h"
#include "Errors.h"
#include "platform_geu_fuse_internal.h"
#include "geu_interface.h"
#include "GEU.h"
#include "ProtocolManager.h"
#include "timer.h"
#include "nza3_fuse_config.h"
/////////////////// Internal Functions ///////////////////
/**
* get fuse configuration spec
*/
// FixME: use generic fuse_conf_spec
static fuse_conf_spec_t GetFuseConfSpec(void* parameter)
{
return nza3_fuse_conf_spec;
}
static UINT_T burn_security_usb_ecc(UINT_T prgecc)
{
UINT_T result;
struct GEU_FuseBurnStatus burn_status;
struct GEU_FuseBurnStatus* pburn_status = &burn_status;
result = GEU_BurnFuseBlock_SecurityUSBIDECC(pburn_status);
return result;
}
/**
* set block seven non-active
*
*/
static void reset_blk7_active_status(void)
{
s_blk_seven_active = 0;
}
/**
* set block seven active
*
*/
static UINT_T set_blk7_active(void)
{
UINT_T result;
if (s_blk_seven_active == 0) {
result = GEU_SetActiveFuseBlock(K_USBID_FUSEBLOCK);
if (result != NoError) {
return result;
}
s_blk_seven_active = 1;
}
return NoError;
}
/**
* Attention: this function must kept consistent with what is done by Boot ROM,
* for exmaple, the pack order for public key
* perform platform binding
* @parameter ptim: pointer to TIM
* @parameter parameter: should be NULL
* @return: FUSE_FuseBurnPowerNotEnabled if UsbPhy band gap is not enabled
* other error code otherwise
*
* Note: Due to the need of provisioning of non-trusted platform and minimize
* the code size, we have a dummy implementation of this function for
* non-trusted case.
*/
// FixME: set algorithm id using info form TIM
extern UINT_T GEU_LIB_BindPlatform(pTIM ptim, void* parameter)
{
UINT_T result = NoError;
UINT_T key_word_cnt, hash_data_size_in_bytes;
UINT_T data[BINDKEYSIZE] = {0};
UINT_T fusedata[DIGEST_WLEN_MAX];
UINT_T digest[DIGEST_WLEN_MAX];
struct GEU_FuseBurnStatus burn_status;
struct GEU_FuseBurnStatus* pburn_status = &burn_status;
UINT_T programmed = 0;
UINT_T i;
pSECURITY_FUNCTIONS pSFs = GetSecurityFunctionsPointer();
if (parameter != NULL) {
s_uart_logger = (logger) parameter;
}
GEU_UARTLOG("S OEMKeyHash...\n");
result = GEU_ReadOemHashKeyFuseBits(fusedata, K_SHA256_SIZE);
if (result != NoError) {
return result;
}
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != 0) {
programmed = 1;
break;
}
}
if (ptim->pConsTIM->VersionBind.Version < (TIM_3_4_00)) {
/* do not support TIM_3_3_00 and TIM_3_2_00 anymore */
return InvalidTIMVersionError;
}
/* compute platform verification key digest */
/* after TIM version 3.2.00 all key size is in bit */
key_word_cnt = ptim->pTBTIM_DS->KeySize / 32;
hash_data_size_in_bytes = (key_word_cnt*2 + 1) * 4; // (crypto_scheme||modulus-or-X||exponent-or-Y) in bytes (*4)
// 1) Pack the crypto_scheme
//crypto_scheme: 0x0000A100 PKCSv1_SHA1_1024RSA
// 0x0000A110 PKCSv1_SHA256_1024RSA
// 0x0000A200 PKCSv1_SHA1_2048RSA
// 0x0000A210 PKCSv1_SHA256_2048RSA
if(ptim->pTBTIM_DS->HashAlgorithmID == SHA256)
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA256_2048RSA : PKCSv1_SHA256_1024RSA;
else // Defaults to 160
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA1_2048RSA : PKCSv1_SHA1_1024RSA;
// 2) Pack the Modulus and Exponent
for (i=0; i < key_word_cnt; i++)
{
data[i+1] = ptim->pTBTIM_DS->Rsa.RSAModulus[i];
data[i+key_word_cnt+1] = ptim->pTBTIM_DS->Rsa.RSAPublicExponent[i];
}
//Key Padding is on by default
hash_data_size_in_bytes = BINDKEYSIZE*4; // MaxKeySize*2+CryptoScheme in Bytes: 129*4 = 516
/* compute digest */
for (i = 0; i < DIGEST_WLEN_MAX; i++) {
digest[i] = 0;
}
result = pSFs->pSHAMessageDigest((UINT8_T *)data, hash_data_size_in_bytes,
(UINT8_T *)digest, ptim->pTBTIM_DS->HashAlgorithmID);
if (result != NoError) {
return result;
}
/* allow reprogramming as it is often the case during development */
if (programmed) {
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != digest[i]) {
return FUSE_BurnError;
}
}
return NoError;
}
/* make sure power supply required for fuse programming is enabled */
result = GEU_EnableFuseBurnPower();
if (result != NoError) {
return FUSE_FuseBurnPowerNotEnabled;
}
/* go burn the platform key hash */
result = GEU_SetActiveFuseBlock(K_OEM_FUSEBLOCK);
if (result != NoError) {
return result;
}
result = GEU_SetupOemHashKeyFuseBits(digest, 4 * DIGEST_WLEN_MAX);
if (result != NoError) {
return result;
}
result = GEU_BurnFuseBlock_OemHashKey(pburn_status);
if (result != NoError) {
return result;
}
GEU_UARTLOG("E OEMKeyHash.\n");
return result;
}
// This function is called from OBM
// Fully Implemented in WTM
// Always returns NoError for GEU
extern UINT_T GEU_LIB_VerifyPlatform(pTIM ptim)
{
UINT_T result;
UINT_T key_word_cnt, hash_data_size_in_bytes;
UINT_T data[BINDKEYSIZE]= {0};
UINT_T fusedata[DIGEST_WLEN_MAX];
UINT_T digest[DIGEST_WLEN_MAX];
UINT_T programmed = 0;
UINT_T i;
pSECURITY_FUNCTIONS pSFs = GetSecurityFunctionsPointer();
result = GEU_ReadOemHashKeyFuseBits(fusedata, K_SHA256_SIZE);
if (result != NoError) {
return result;
}
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != 0) {
programmed = 1;
break;
}
}
if (ptim->pConsTIM->VersionBind.Version < (TIM_3_4_00)) {
/* do not support TIM_3_3_00 and TIM_3_2_00 anymore */
return InvalidTIMVersionError;
}
/* after TIM version 3.2.00 all key size is in bit */
key_word_cnt = ptim->pTBTIM_DS->KeySize / 32;
hash_data_size_in_bytes = (key_word_cnt*2 + 1) * 4; // (crypto_scheme||modulus-or-X||exponent-or-Y) in bytes (*4)
// 1) Pack the crypto_scheme
//crypto_scheme: 0x0000A100 PKCSv1_SHA1_1024RSA
// 0x0000A110 PKCSv1_SHA256_1024RSA
// 0x0000A200 PKCSv1_SHA1_2048RSA
// 0x0000A210 PKCSv1_SHA256_2048RSA
if(ptim->pTBTIM_DS->HashAlgorithmID == SHA256)
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA256_2048RSA : PKCSv1_SHA256_1024RSA;
else // Defaults to 160
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA1_2048RSA : PKCSv1_SHA1_1024RSA;
// 2) Pack the Modulus and Exponent
for (i=0; i < key_word_cnt; i++)
{
data[i+1] = ptim->pTBTIM_DS->Rsa.RSAModulus[i];
data[i+key_word_cnt+1] = ptim->pTBTIM_DS->Rsa.RSAPublicExponent[i];
}
//Key Padding is on by default
hash_data_size_in_bytes = BINDKEYSIZE*4; // MaxKeySize*2+CryptoScheme in Bytes: 129*4 = 516
/* compute digest */
for (i = 0; i < DIGEST_WLEN_MAX; i++) {
digest[i] = 0;
}
result = pSFs->pSHAMessageDigest((UINT8_T *)data, hash_data_size_in_bytes,
(UINT8_T *)digest, ptim->pTBTIM_DS->HashAlgorithmID);
if (result != NoError) {
return result;
}
/* compare fuses against TIM */
if (programmed) {
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != digest[i]) {
return FUSE_FuseBlockCompareFailed;
}
}
}
return NoError;
}
/**
* program jtag key using data from {key, len} of pTIM
* @parameter key: pointer to key
* @parameter len: key length
* @parameter ptim: pointer to tim
* @parameter: should be NULL
*
* Note: Due to the need of provisioning of non-trusted platform and minimize
* the code size, we have a dummy implementation of this function for
* non-trusted case.
*/
// FixME: set algorithm id using info form TIM
extern UINT_T GEU_LIB_BindJTAGKey(pTIM ptim, void* parameter)
{
UINT_T result;
UINT_T key_word_cnt, hash_data_size_in_bytes;
//pKEY_MOD_3_2_0 pTimKey;
pKEY_MOD_3_4_0 pkey;
UINT_T data[BINDKEYSIZE] = {0};
UINT_T fusedata[DIGEST_WLEN_MAX];
UINT_T digest[DIGEST_WLEN_MAX];
struct GEU_FuseBurnStatus burn_status;
struct GEU_FuseBurnStatus* pburn_status = &burn_status;
UINT_T programmed = 0;
UINT_T i;
UINT_T HashAlgorithmID;
UINT_T EncryptAlgorithmID;
UINT_T KeySize;
pSECURITY_FUNCTIONS pSFs = GetSecurityFunctionsPointer();
GEU_UARTLOG("S JTAGKeyHash...\n");
pkey = FindKeyInTIM(ptim, JTAGIDENTIFIER);
if ( pkey == NULL )
{
return NoError;
}
result = GEU_ReadOemJtagHashKeyFuseBits(fusedata, K_SHA256_SIZE);
if (result != NoError) {
return result;
}
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != 0) {
programmed = 1;
break;
}
}
if (ptim->pConsTIM->VersionBind.Version < (TIM_3_4_00)) {
return InvalidTIMVersionError;
}
// /* compute jtag enable key digest */
// if (ptim->pConsTIM->VersionBind.Version < (TIM_3_3_00)) {
// /* before and with TIM version 3.2.00 all key size is in byte */
// key_word_cnt = ptim->pTBTIM_DS->KeySize/4;
// }
// else {
// /* after TIM version 3.2.00 all key size is in bit */
// key_word_cnt = ptim->pTBTIM_DS->KeySize / 32;
// }
HashAlgorithmID = pkey->HashAlgorithmID;
KeySize = pkey->KeySize;
EncryptAlgorithmID = pkey->EncryptAlgorithmID;
key_word_cnt = KeySize/32;
#if EMEI
hash_data_size_in_bytes = key_word_cnt *2*4; // (exponent-or-X||modulus-or-Y) in bytes (*4)
/* pack the Exponent */
for (i = 0; i < key_word_cnt; i++) {
data[i] = ptim->pTBTIM_DS->Rsa.RSAPublicExponent[i];
}
/* pack the Modulus */
for (i = 0; i < key_word_cnt; i++) {
data[i + key_word_cnt] = ptim->pTBTIM_DS->Rsa.RSAModulus[i];
}
#else //HELN
hash_data_size_in_bytes = (key_word_cnt*2 + 1) * 4; // (crypto_scheme||modulus-or-X||exponent-or-Y) in bytes (*4)
//for platforms other than EMEI, like HELN use 3_4 TIM and beyond
if (EncryptAlgorithmID == PKCS1_v1_5_Ippcp)
{
// 1) Pack the crypto_scheme
//crypto_scheme: 0x0000A100 PKCSv1_SHA1_1024RSA
// 0x0000A110 PKCSv1_SHA256_1024RSA
// 0x0000A200 PKCSv1_SHA1_2048RSA
// 0x0000A210 PKCSv1_SHA256_2048RSA
if(ptim->pTBTIM_DS->HashAlgorithmID == SHA256)
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA256_2048RSA : PKCSv1_SHA256_1024RSA;
else // Defaults to 160
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA1_2048RSA : PKCSv1_SHA1_1024RSA;
// 2) Pack the Modulus and Exponent
for (i=0; i < key_word_cnt; i++)
{
data[i+1] = ptim->pTBTIM_DS->Rsa.RSAModulus[i];
data[i+key_word_cnt+1] = ptim->pTBTIM_DS->Rsa.RSAPublicExponent[i];
}
}
else
return InvalidDSAError;
#endif
//Key Padding is on by default
hash_data_size_in_bytes = BINDKEYSIZE*4; // MaxKeySize*2+CryptoScheme in Bytes: 129*4 = 516
for (i = 0; i < DIGEST_WLEN_MAX; i++) {
digest[i] = 0;
}
result = pSFs->pSHAMessageDigest((UINT8_T *)data, hash_data_size_in_bytes,
(UINT8_T *)digest, HashAlgorithmID);
if (result != NoError) {
return result;
}
/* allow reprogramming as it is often the case during development */
if (programmed) {
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != digest[i]) {
return FUSE_FuseReprogrammingError;
}
}
return NoError;
}
/* make sure power supply required for fuse programming is enabled */
result = GEU_EnableFuseBurnPower();
if (result != NoError) {
return FUSE_FuseBurnPowerNotEnabled;
}
// go burn the platform key hash
result = GEU_SetActiveFuseBlock(K_JTAG_FUSEBLOCK);
if (result != NoError) {
return result;
}
result = GEU_SetupOemJtagHashKeyFuseBits(digest, 4 * DIGEST_WLEN_MAX);
if (result != NoError) {
return result;
}
result = GEU_BurnFuseBlock_OemJtagHashKey(pburn_status);
if (result != NoError) {
return result;
}
GEU_UARTLOG("E JTAGKeyHash.\n");
GEU_UARTLOG("S JTAGKeyHashECC...\n");
result = GEU_BurnECC(pburn_status);
GEU_UARTLOG("E JTAGKeyHashECC.\n");
return result;
}
/**
* Not Implemented for GEU
* @return: always NoError
*/
extern UINT_T GEU_LIB_VerifyJTAGKey(pTIM ptim)
{
UINT_T result;
UINT_T key_word_cnt, hash_data_size_in_bytes;
//pKEY_MOD_3_2_0 pTimKey;
pKEY_MOD_3_4_0 pkey;
UINT_T data[BINDKEYSIZE] = {0};
UINT_T fusedata[DIGEST_WLEN_MAX];
UINT_T digest[DIGEST_WLEN_MAX];
UINT_T programmed = 0;
UINT_T i;
UINT_T HashAlgorithmID;
UINT_T EncryptAlgorithmID;
UINT_T KeySize;
pSECURITY_FUNCTIONS pSFs = GetSecurityFunctionsPointer();
pkey = FindKeyInTIM(ptim, JTAGIDENTIFIER);
if ( pkey == NULL )
{
return NoError;
}
result = GEU_ReadOemJtagHashKeyFuseBits(fusedata, K_SHA256_SIZE);
if (result != NoError) {
return result;
}
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != 0) {
programmed = 1;
break;
}
}
if (ptim->pConsTIM->VersionBind.Version < (TIM_3_4_00)) {
return InvalidTIMVersionError;
}
HashAlgorithmID = pkey->HashAlgorithmID;
KeySize = pkey->KeySize;
EncryptAlgorithmID = pkey->EncryptAlgorithmID;
key_word_cnt = KeySize/32;
#if EMEI
hash_data_size_in_bytes = key_word_cnt *2*4; // (exponent-or-X||modulus-or-Y) in bytes (*4)
/* pack the Exponent */
for (i = 0; i < key_word_cnt; i++) {
data[i] = ptim->pTBTIM_DS->Rsa.RSAPublicExponent[i];
}
/* pack the Modulus */
for (i = 0; i < key_word_cnt; i++) {
data[i + key_word_cnt] = ptim->pTBTIM_DS->Rsa.RSAModulus[i];
}
#else //HELN
hash_data_size_in_bytes = (key_word_cnt*2 + 1) * 4; // (crypto_scheme||modulus-or-X||exponent-or-Y) in bytes (*4)
//for platforms other than EMEI, like HELN use 3_4 TIM and beyond
if (EncryptAlgorithmID == PKCS1_v1_5_Ippcp)
{
// 1) Pack the crypto_scheme
//crypto_scheme: 0x0000A100 PKCSv1_SHA1_1024RSA
// 0x0000A110 PKCSv1_SHA256_1024RSA
// 0x0000A200 PKCSv1_SHA1_2048RSA
// 0x0000A210 PKCSv1_SHA256_2048RSA
if(ptim->pTBTIM_DS->HashAlgorithmID == SHA256)
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA256_2048RSA : PKCSv1_SHA256_1024RSA;
else // Defaults to 160
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA1_2048RSA : PKCSv1_SHA1_1024RSA;
// 2) Pack the Modulus and Exponent
for (i=0; i < key_word_cnt; i++)
{
data[i+1] = ptim->pTBTIM_DS->Rsa.RSAModulus[i];
data[i+key_word_cnt+1] = ptim->pTBTIM_DS->Rsa.RSAPublicExponent[i];
}
}
else
return InvalidDSAError;
#endif
//Key Padding is on by default
hash_data_size_in_bytes = BINDKEYSIZE*4; // MaxKeySize*2+CryptoScheme in Bytes: 129*4 = 516
for (i = 0; i < DIGEST_WLEN_MAX; i++) {
digest[i] = 0;
}
result = pSFs->pSHAMessageDigest((UINT8_T *)data, hash_data_size_in_bytes,
(UINT8_T *)digest, HashAlgorithmID);
if (result != NoError) {
return result;
}
/* compare fuses against TIM */
if (programmed) {
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != digest[i]) {
return FUSE_FuseBlockCompareFailed;
}
}
}
return NoError;
}
/**
* perform platform auto-configuration
* @parameter ptim: pointer to TIM
* @parameter parameter: NULL
*/
extern UINT_T GEU_LIB_AutoConfigPlatform(pTIM ptim, void* parameter)
{
UINT_T result = NoError;
fuse_conf_spec_t fuse_conf;
fuse_conf = GetFuseConfSpec(NULL);
/* make sure power supply required for fuse programming is enabled */
result = GEU_EnableFuseBurnPower();
if (result != NoError) {
return FUSE_FuseBurnPowerNotEnabled;
}
GEU_UARTLOG("S USBIDSecurityConfig...\n");
//GEU_UARTLOG("S ApCpECC...\n");
// ApCP in block 0
//reset_blk0_active_status();
// Security Config/USB ID in block 7
reset_blk7_active_status();
/*
* configure USB ID, Security Config and their ECCs
*/
result = GEU_LIB_ProgramSecurityConfig(NULL, ptim);
if (result != NoError) {
return result;
}
result = GEU_SetupSecurityConfigUsbIdEccFuseBits();
if (result != NoError) {
return result;
}
result = burn_security_usb_ecc(1);
if ((result != NoError) && (result != FUSE_FuseBlockNotActive) && (result != FUSE_NoBurnRequest)) {
return result;
}
return result;
}
/**
* program security config fuse bits
*/
UINT_T GEU_LIB_ProgramSecurityConfig(void* parameter, pTIM ptim)
{
UINT_T result, flash_number;
UINT_T security_config[1];
fuse_conf_spec_t fuse_conf;
fuse_conf = GetFuseConfSpec(NULL);
result = set_blk7_active();
result = GEU_ReadSecurityConfigFuseBits(&security_config[0], K_SECURITY_CONFIG_FUSE_SIZE);
if (result != NoError) {
return result;
}
if (ptim != NULL) {
flash_number = (UINT8_T)((ptim->pConsTIM->FlashInfo.BootFlashSign) & 0x3F);
fuse_conf.security_config[0] |= flash_number << FLASHNUMSHIFT;
}
if (ptim != NULL) {
if (ptim->pConsTIM->VersionBind.Trusted)
fuse_conf.security_config[0] |= (OPMODETRUSTED); // Trusted
else
fuse_conf.security_config[0] |= (OPMODENONTRUSTED); // Non-Trusted
}
if ( security_config[0]!= 0 && security_config[0] != fuse_conf.security_config[0] ) {
return FUSE_FuseBlockFieldFull;
}
result = GEU_SetupSecurityConfigFuseBits(&fuse_conf.security_config[0], fuse_conf.security_config_bit_cnt/8);
return result;
}
UINT_T GEU_ProgramMiscConfig(pTIM pTIM_h)
{
(VOID)pTIM_h;
return NoError;
}