562 lines
17 KiB
C
562 lines
17 KiB
C
/**************************************************************************//**
|
|
* @file keystore.c
|
|
* @version V3.00
|
|
* @brief Key store driver source file
|
|
*
|
|
* @copyright SPDX-License-Identifier: Apache-2.0
|
|
* @copyright Copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
|
|
*****************************************************************************/
|
|
#include "NuMicro.h"
|
|
/** @addtogroup Standard_Driver Standard Driver
|
|
@{
|
|
*/
|
|
|
|
/** @addtogroup KS_Driver Key Store Driver
|
|
@{
|
|
*/
|
|
|
|
|
|
/** @addtogroup KS_EXPORTED_FUNCTIONS Key Store Exported Functions
|
|
@{
|
|
*/
|
|
|
|
/**
|
|
* @brief Initial key store
|
|
* @return None
|
|
* @details This function is used to initial the key store.
|
|
* It is necessary to be called before using other APIs of Key Store.
|
|
*/
|
|
void KS_Open(void)
|
|
{
|
|
if((KS->STS & KS_STS_INITDONE_Msk) == 0)
|
|
{
|
|
/* Waiting for busy */
|
|
while(KS->STS & KS_STS_BUSY_Msk) {}
|
|
|
|
/* Start Key Store Initial */
|
|
KS->CTL = KS_CTL_INIT_Msk | KS_CTL_START_Msk;
|
|
|
|
/* Waiting for initilization */
|
|
while((KS->STS & KS_STS_INITDONE_Msk) == 0);
|
|
|
|
}
|
|
|
|
/* Waiting busy to make sure KS is ready. */
|
|
while(KS->STS & KS_STS_BUSY_Msk);
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Read key from key store
|
|
* @param[in] eType The memory type. It could be:
|
|
\ref KS_SRAM
|
|
\ref KS_FLASH
|
|
\ref KS_OTP
|
|
* @param[in] i32KeyIdx The key index to read
|
|
* @param[out] au32Key The buffer to store the key
|
|
* @param[in] u32WordCnt The word (32-bit) count of the key buffer size
|
|
* @retval 0 Successful
|
|
* @retval -1 Fail
|
|
* @details This function is used to read the key.
|
|
*/
|
|
|
|
int32_t KS_Read(KS_MEM_Type eType, int32_t i32KeyIdx, uint32_t au32Key[], uint32_t u32WordCnt)
|
|
{
|
|
int32_t i32Cnt;
|
|
uint32_t u32Cont;
|
|
int32_t offset, i, cnt;
|
|
|
|
/* Just return when key store is in busy */
|
|
if(KS->STS & KS_STS_BUSY_Msk)
|
|
return -1;
|
|
|
|
/* Specify the key address */
|
|
KS->METADATA = ((uint32_t)eType << KS_METADATA_DST_Pos) | KS_TOMETAKEY(i32KeyIdx);
|
|
|
|
/* Clear error flag */
|
|
KS->STS = KS_STS_EIF_Msk;
|
|
offset = 0;
|
|
u32Cont = 0;
|
|
i32Cnt = (int32_t)u32WordCnt;
|
|
do
|
|
{
|
|
/* Clear Status */
|
|
KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk;
|
|
|
|
/* Trigger to read the key */
|
|
KS->CTL = u32Cont | KS_OP_READ | KS_CTL_START_Msk | (KS->CTL & (KS_CTL_SILENT_Msk | KS_CTL_SCMB_Msk));
|
|
/* Waiting for key store processing */
|
|
while(KS->STS & KS_STS_BUSY_Msk);
|
|
|
|
/* Read the key to key buffer */
|
|
cnt = i32Cnt;
|
|
if(cnt > 8)
|
|
cnt = 8;
|
|
for(i = 0; i < cnt; i++)
|
|
{
|
|
au32Key[offset + i] = KS->KEY[i];
|
|
//printf("R[%d]:0x%08x\n", i, au32Key[offset+i]);
|
|
}
|
|
|
|
u32Cont = KS_CTL_CONT_Msk;
|
|
i32Cnt -= 8;
|
|
offset += 8;
|
|
}
|
|
while(i32Cnt > 0);
|
|
|
|
/* Check error flag */
|
|
if(KS->STS & KS_STS_EIF_Msk)
|
|
return -1;
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* @brief Get the word count of the specified Metadata key length
|
|
* @param[in] u32Meta The metadata define of the key length. It could be
|
|
\ref KS_META_128
|
|
\ref KS_META_163
|
|
\ref KS_META_192
|
|
\ref KS_META_224
|
|
\ref KS_META_233
|
|
\ref KS_META_255
|
|
\ref KS_META_256
|
|
\ref KS_META_283
|
|
\ref KS_META_384
|
|
\ref KS_META_409
|
|
\ref KS_META_512
|
|
\ref KS_META_521
|
|
\ref KS_META_571
|
|
\ref KS_META_1024
|
|
\ref KS_META_2048
|
|
\ref KS_META_4096
|
|
* @return The word (32-bit) count of the key
|
|
* @details This function is used to get word counts of the specified metadata key length.
|
|
* It could be used to know how may words needs to allocate for the key.
|
|
*/
|
|
|
|
uint32_t KS_GetKeyWordCnt(uint32_t u32Meta)
|
|
{
|
|
const uint16_t au8CntTbl[21] = { 4, 6, 6, 7, 8, 8, 8, 9, 12, 13, 16, 17, 18, 0, 0, 0, 32, 48, 64, 96, 128 };
|
|
return au8CntTbl[((u32Meta & KS_METADATA_SIZE_Msk) >> KS_METADATA_SIZE_Pos)];
|
|
}
|
|
|
|
/**
|
|
* @brief Write key to key store
|
|
* @param[in] eType The memory type. It could be:
|
|
\ref KS_SRAM
|
|
\ref KS_FLASH
|
|
* @param[in] u32Meta The metadata of the key. It could be the combine of
|
|
\ref KS_META_AES
|
|
\ref KS_META_HMAC
|
|
\ref KS_META_RSA_EXP
|
|
\ref KS_META_RSA_MID
|
|
\ref KS_META_ECC
|
|
\ref KS_META_CPU
|
|
\ref KS_META_128
|
|
\ref KS_META_163
|
|
\ref KS_META_192
|
|
\ref KS_META_224
|
|
\ref KS_META_233
|
|
\ref KS_META_255
|
|
\ref KS_META_256
|
|
\ref KS_META_283
|
|
\ref KS_META_384
|
|
\ref KS_META_409
|
|
\ref KS_META_512
|
|
\ref KS_META_521
|
|
\ref KS_META_571
|
|
\ref KS_META_1024
|
|
\ref KS_META_2048
|
|
\ref KS_META_4096
|
|
\ref KS_META_BOOT
|
|
\ref KS_META_READABLE
|
|
\ref KS_META_PRIV
|
|
\ref KS_META_NONPRIV
|
|
\ref KS_META_SECURE
|
|
\ref KS_META_NONSECUR
|
|
|
|
* @param[out] au32Key The buffer to store the key
|
|
* @param[in] u32WordCnt The word (32-bit) count of the key buffer size
|
|
* @return Index of the key. Failed when index < 0.
|
|
* @details This function is used to write a key to key store.
|
|
*/
|
|
|
|
int32_t KS_Write(KS_MEM_Type eType, uint32_t u32Meta, uint32_t au32Key[])
|
|
{
|
|
int32_t i32Cnt;
|
|
uint32_t u32Cont;
|
|
int32_t offset, i, cnt;
|
|
|
|
|
|
/* Just return when key store is in busy */
|
|
if(KS->STS & KS_STS_BUSY_Msk)
|
|
return -1;
|
|
|
|
/* Specify the key address */
|
|
KS->METADATA = (eType << KS_METADATA_DST_Pos) | u32Meta;
|
|
|
|
/* Get size index */
|
|
i32Cnt = (int32_t)KS_GetKeyWordCnt(u32Meta);
|
|
|
|
/* Invalid key length */
|
|
if(i32Cnt == 0)
|
|
return -1;
|
|
|
|
/* OTP only support maximum 256 bits */
|
|
if((eType == KS_OTP) && (i32Cnt > 8))
|
|
return -1;
|
|
|
|
/* Clear error flag */
|
|
KS->STS = KS_STS_EIF_Msk;
|
|
offset = 0;
|
|
u32Cont = 0;
|
|
do
|
|
{
|
|
/* Prepare the key to write */
|
|
cnt = i32Cnt;
|
|
if(cnt > 8)
|
|
cnt = 8;
|
|
for(i = 0; i < cnt; i++)
|
|
{
|
|
KS->KEY[i] = au32Key[offset + i];
|
|
}
|
|
|
|
/* Clear Status */
|
|
KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk;
|
|
|
|
/* Write the key */
|
|
KS->CTL = u32Cont | KS_OP_WRITE | KS_CTL_START_Msk | (KS->CTL & (KS_CTL_SILENT_Msk | KS_CTL_SCMB_Msk));
|
|
|
|
u32Cont = KS_CTL_CONT_Msk;
|
|
i32Cnt -= 8;
|
|
offset += 8;
|
|
|
|
/* Waiting for key store processing */
|
|
while(KS->STS & KS_STS_BUSY_Msk);
|
|
|
|
}
|
|
while(i32Cnt > 0);
|
|
|
|
/* Check error flag */
|
|
if(KS->STS & KS_STS_EIF_Msk)
|
|
{
|
|
//printf("KS_Write. EIF!\n");
|
|
return -1;
|
|
}
|
|
|
|
return KS_TOKEYIDX(KS->METADATA);
|
|
}
|
|
|
|
/**
|
|
* @brief Erase a key from key store
|
|
* @param[in] i32KeyIdx The key index to read
|
|
* @retval 0 Successful
|
|
* @retval -1 Fail
|
|
* @details This function is used to erase a key from SRAM of key store.
|
|
*/
|
|
int32_t KS_EraseKey(int32_t i32KeyIdx)
|
|
{
|
|
/* Just return when key store is in busy */
|
|
if(KS->STS & KS_STS_BUSY_Msk)
|
|
return -1;
|
|
|
|
/* Clear error flag */
|
|
KS->STS = KS_STS_EIF_Msk;
|
|
|
|
/* Specify the key address */
|
|
KS->METADATA = (KS_SRAM << KS_METADATA_DST_Pos) | KS_TOMETAKEY(i32KeyIdx);
|
|
|
|
/* Clear Status */
|
|
KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk;
|
|
|
|
/* Erase the key */
|
|
KS->CTL = KS_OP_ERASE | KS_CTL_START_Msk | (KS->CTL & (KS_CTL_SILENT_Msk | KS_CTL_SCMB_Msk));
|
|
|
|
/* Waiting for processing */
|
|
while(KS->STS & KS_STS_BUSY_Msk);
|
|
|
|
/* Check error flag */
|
|
if(KS->STS & KS_STS_EIF_Msk)
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Erase all keys from key store
|
|
* @param[in] eType The memory type. It could be:
|
|
\ref KS_SRAM
|
|
\ref KS_FLASH
|
|
\ref KS_OTP
|
|
* @param[in] i32KeyIdx The key index to read
|
|
* @retval 0 Successful
|
|
* @retval -1 Fail
|
|
* @details This function is used to erase all keys in SRAM or Flash of key store.
|
|
*/
|
|
int32_t KS_EraseAll(KS_MEM_Type eType)
|
|
{
|
|
/* Just return when key store is in busy */
|
|
if(KS->STS & KS_STS_BUSY_Msk)
|
|
return -1;
|
|
|
|
/* Clear error flag */
|
|
KS->STS = KS_STS_EIF_Msk;
|
|
|
|
/* Specify the key address */
|
|
KS->METADATA = (eType << KS_METADATA_DST_Pos);
|
|
|
|
/* Clear Status */
|
|
KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk;
|
|
|
|
/* Erase the key */
|
|
KS->CTL = KS_OP_ERASE_ALL | KS_CTL_START_Msk | (KS->CTL & (KS_CTL_SILENT_Msk | KS_CTL_SCMB_Msk));
|
|
|
|
/* Waiting for processing */
|
|
while(KS->STS & KS_STS_BUSY_Msk);
|
|
|
|
/* Check error flag */
|
|
if(KS->STS & KS_STS_EIF_Msk)
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief Revoke a key in key store
|
|
* @param[in] eType The memory type. It could be:
|
|
\ref KS_SRAM
|
|
\ref KS_FLASH
|
|
\ref KS_OTP
|
|
* @param[in] i32KeyIdx The key index to read
|
|
* @retval 0 Successful
|
|
* @retval -1 Fail
|
|
* @details This function is used to revoke a key in key store.
|
|
*/
|
|
int32_t KS_RevokeKey(KS_MEM_Type eType, int32_t i32KeyIdx)
|
|
{
|
|
/* Just return when key store is in busy */
|
|
if(KS->STS & KS_STS_BUSY_Msk)
|
|
return -1;
|
|
|
|
/* Clear error flag */
|
|
KS->STS = KS_STS_EIF_Msk;
|
|
|
|
/* Specify the key address */
|
|
KS->METADATA = (eType << KS_METADATA_DST_Pos) | KS_TOMETAKEY(i32KeyIdx);
|
|
|
|
/* Clear Status */
|
|
KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk;
|
|
|
|
/* Erase the key */
|
|
KS->CTL = KS_OP_REVOKE | KS_CTL_START_Msk | (KS->CTL & (KS_CTL_SILENT_Msk | KS_CTL_SCMB_Msk));
|
|
|
|
/* Waiting for processing */
|
|
while(KS->STS & KS_STS_BUSY_Msk);
|
|
|
|
/* Check error flag */
|
|
if(KS->STS & KS_STS_EIF_Msk)
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Get remain size of specified Key Store memory
|
|
* @param[in] eType The memory type. It could be:
|
|
\ref KS_SRAM
|
|
\ref KS_FLASH
|
|
* @retval remain size of specified Key Store memory
|
|
* @details This function is used to get remain size of Key Store.
|
|
*/
|
|
uint32_t KS_GetRemainSize(KS_MEM_Type mem)
|
|
{
|
|
uint32_t u32Reg;
|
|
uint32_t u32SramRemain, u32FlashRemain;
|
|
|
|
u32Reg = KS->REMAIN;
|
|
//printf("KS Remain 0x%08x\n", u32Reg);
|
|
//printf("SRAM remain %lu bytes, Flash remain %lu bytes\n",(u32Reg&KS_REMAIN_RRMNG_Msk) >> KS_REMAIN_RRMNG_Pos, (u32Reg&KS_REMAIN_FRMNG_Msk) >> KS_REMAIN_FRMNG_Pos);
|
|
u32SramRemain = (u32Reg & KS_REMAIN_RRMNG_Msk) >> KS_REMAIN_RRMNG_Pos;
|
|
u32FlashRemain = (u32Reg & KS_REMAIN_FRMNG_Msk) >> KS_REMAIN_FRMNG_Pos;
|
|
|
|
if(mem == KS_SRAM)
|
|
return u32SramRemain;
|
|
else
|
|
return u32FlashRemain;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief Get remain key count of specified Key Store memory
|
|
* @param[in] eType The memory type. It could be:
|
|
\ref KS_SRAM
|
|
\ref KS_FLASH
|
|
* @retval Remain key count in the specified key store memory
|
|
* @details This function is used to get remain key count in specified key store memory.
|
|
*/
|
|
uint32_t KS_GetRemainKeyCount(KS_MEM_Type mem)
|
|
{
|
|
uint32_t u32Reg;
|
|
uint32_t u32SramRemain, u32FlashRemain;
|
|
|
|
u32Reg = KS->REMKCNT;
|
|
u32SramRemain = (u32Reg & KS_REMKCNT_RRMKCNT_Msk) >> KS_REMKCNT_RRMKCNT_Pos;
|
|
u32FlashRemain = (u32Reg & KS_REMKCNT_FRMKCNT_Msk) >> KS_REMKCNT_FRMKCNT_Pos;
|
|
|
|
if(mem == KS_SRAM)
|
|
return u32SramRemain;
|
|
else
|
|
return u32FlashRemain;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* @brief Write OTP key to key store
|
|
* @param[in] i32KeyIdx The OTP key index to store the key. It could be 0~7.
|
|
OTP key index 0 is default for ROTPK.
|
|
* @param[in] u32Meta The metadata of the key. It could be the combine of
|
|
\ref KS_META_AES
|
|
\ref KS_META_HMAC
|
|
\ref KS_META_RSA_EXP
|
|
\ref KS_META_RSA_MID
|
|
\ref KS_META_ECC
|
|
\ref KS_META_CPU
|
|
\ref KS_META_128
|
|
\ref KS_META_163
|
|
\ref KS_META_192
|
|
\ref KS_META_224
|
|
\ref KS_META_233
|
|
\ref KS_META_255
|
|
\ref KS_META_256
|
|
\ref KS_META_BOOT
|
|
\ref KS_META_READABLE
|
|
\ref KS_META_PRIV
|
|
\ref KS_META_NONPRIV
|
|
\ref KS_META_SECURE
|
|
\ref KS_META_NONSECUR
|
|
|
|
* @param[out] au32Key The buffer to store the key
|
|
* @param[in] u32WordCnt The word (32-bit) count of the key buffer size
|
|
* @retval 0 Successful
|
|
* @retval -1 Fail
|
|
* @details This function is used to write a key to OTP key store.
|
|
*/
|
|
int32_t KS_WriteOTP(int32_t i32KeyIdx, uint32_t u32Meta, uint32_t au32Key[])
|
|
{
|
|
const uint16_t au8CntTbl[7] = {4, 6, 6, 7, 8, 8, 8};
|
|
int32_t i32Cnt;
|
|
uint32_t u32Cont;
|
|
int32_t offset, i, cnt, sidx;
|
|
|
|
|
|
/* Just return when key store is in busy */
|
|
if(KS->STS & KS_STS_BUSY_Msk)
|
|
return -1;
|
|
|
|
/* Specify the key address */
|
|
KS->METADATA = ((uint32_t)KS_OTP << KS_METADATA_DST_Pos) | u32Meta | KS_TOMETAKEY(i32KeyIdx);
|
|
|
|
/* Get size index */
|
|
sidx = (u32Meta >> KS_METADATA_SIZE_Pos) & 0xful;
|
|
|
|
/* OTP only support maximum 256 bits */
|
|
if(sidx >= 7)
|
|
return -1;
|
|
|
|
i32Cnt = au8CntTbl[sidx];
|
|
|
|
/* Clear error flag */
|
|
KS->STS = KS_STS_EIF_Msk;
|
|
offset = 0;
|
|
u32Cont = 0;
|
|
do
|
|
{
|
|
/* Prepare the key to write */
|
|
cnt = i32Cnt;
|
|
if(cnt > 8)
|
|
cnt = 8;
|
|
for(i = 0; i < cnt; i++)
|
|
{
|
|
KS->KEY[i] = au32Key[offset + i];
|
|
}
|
|
|
|
/* Clear Status */
|
|
KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk;
|
|
|
|
/* Write the key */
|
|
KS->CTL = u32Cont | KS_OP_WRITE | KS_CTL_START_Msk | (KS->CTL & (KS_CTL_SILENT_Msk | KS_CTL_SCMB_Msk));
|
|
|
|
u32Cont = KS_CTL_CONT_Msk;
|
|
i32Cnt -= 8;
|
|
offset += 8;
|
|
|
|
/* Waiting for key store processing */
|
|
while(KS->STS & KS_STS_BUSY_Msk);
|
|
|
|
}
|
|
while(i32Cnt > 0);
|
|
|
|
/* Check error flag */
|
|
if(KS->STS & KS_STS_EIF_Msk)
|
|
{
|
|
//printf("KS_WriteOTP. EIF!\n");
|
|
return -1;
|
|
}
|
|
|
|
return i32KeyIdx;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Trigger to inverse the date in KS_SRAM.
|
|
* @retval 1 The data in KS SRAM is inverted.
|
|
* @retval 0 The data in KS SRAM is non-inverted.
|
|
* @retval -1 Fail to invert the date in KS SRAM.
|
|
* @details This function is used to trigger anti-remanence procedure by inverse the data in SRAM.
|
|
* This won't change the reading key.
|
|
*/
|
|
|
|
int32_t KS_ToggleSRAM(void)
|
|
{
|
|
/* Just return when key store is in busy */
|
|
if(KS->STS & KS_STS_BUSY_Msk)
|
|
return -1;
|
|
|
|
|
|
/* Specify the key address */
|
|
KS->METADATA = ((uint32_t)KS_SRAM << KS_METADATA_DST_Pos);
|
|
|
|
/* Clear error flag */
|
|
KS->STS = KS_STS_EIF_Msk | KS_STS_IF_Msk;
|
|
/* Trigger to do anti-remanence procedure */
|
|
KS->CTL = KS_OP_REMAN | KS_CTL_START_Msk;
|
|
|
|
/* Waiting for key store processing */
|
|
while(KS->STS & KS_STS_BUSY_Msk);
|
|
|
|
/* Check error flag */
|
|
if(KS->STS & KS_STS_EIF_Msk)
|
|
return -1;
|
|
|
|
return ((KS->STS & KS_STS_RAMINV_Msk) > 0);
|
|
}
|
|
|
|
|
|
/**@}*/ /* end of group KS_EXPORTED_FUNCTIONS */
|
|
|
|
/**@}*/ /* end of group KS_Driver */
|
|
|
|
/**@}*/ /* end of group Standard_Driver */
|