diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a6cffbdd..fdc3bb22 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,13 +17,9 @@ jobs: - name: Install extra tools run: | sudo apt-get update - sudo apt-get install -y make build-essential libncurses5-dev libssl-dev libcurl4-openssl-dev wget + sudo apt-get install -y make build-essential libncurses5-dev libssl-dev libcurl4-openssl-dev - name: Build the project run: | make PLATFORM=${{ matrix.platform }} create_context - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/main.c -O ./arch/cortex-m23/m2351/src/NuBL2/main.c - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/VerifyNuBL3x.c -O ./arch/cortex-m23/m2351/src/NuBL2/VerifyNuBL3x.c - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/NuBL2.h -O ./arch/cortex-m23/m2351/src/NuBL2/NuBL2.h - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/FwInfo/FwInfo.c -O ./arch/cortex-m23/m2351/src/NuBL2/FwInfo.c make toolchain make \ No newline at end of file diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a6cd3cf1..0894d031 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -77,15 +77,11 @@ jobs: - name: Install extra tools run: | sudo apt-get update - sudo apt-get install -y make build-essential libncurses5-dev libssl-dev libcurl4-openssl-dev wget + sudo apt-get install -y make build-essential libncurses5-dev libssl-dev libcurl4-openssl-dev - name: Build the project run: | make PLATFORM=numaker_pfm_m2351 create_context - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/main.c -O ./arch/cortex-m23/m2351/src/NuBL2/main.c - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/VerifyNuBL3x.c -O ./arch/cortex-m23/m2351/src/NuBL2/VerifyNuBL3x.c - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/NuBL2.h -O ./arch/cortex-m23/m2351/src/NuBL2/NuBL2.h - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/FwInfo/FwInfo.c -O ./arch/cortex-m23/m2351/src/NuBL2/FwInfo.c make toolchain make diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1d9dd7b0..c9c67008 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -30,14 +30,10 @@ jobs: - name: Install extra tools run: | sudo apt-get update - sudo apt-get install -y make build-essential libncurses5-dev libssl-dev libcurl4-openssl-dev wget + sudo apt-get install -y make build-essential libncurses5-dev libssl-dev libcurl4-openssl-dev - name: Build the project run: | make PLATFORM=numaker_pfm_m2351 create_context - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/main.c -O ./arch/cortex-m23/m2351/src/NuBL2/main.c - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/VerifyNuBL3x.c -O ./arch/cortex-m23/m2351/src/NuBL2/VerifyNuBL3x.c - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/NuBL2.h -O ./arch/cortex-m23/m2351/src/NuBL2/NuBL2.h - wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/FwInfo/FwInfo.c -O ./arch/cortex-m23/m2351/src/NuBL2/FwInfo.c make toolchain make # Save the location of the mtower_*.bin output files for easier reference diff --git a/arch/cortex-m23/m2351/src/NuBL2/.gitignore b/arch/cortex-m23/m2351/src/NuBL2/.gitignore deleted file mode 100644 index c3edecc2..00000000 --- a/arch/cortex-m23/m2351/src/NuBL2/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -FwInfo.c -NuBL2.h -VerifyNuBL3x.c -main.c diff --git a/arch/cortex-m23/m2351/src/NuBL2/FwInfo.c b/arch/cortex-m23/m2351/src/NuBL2/FwInfo.c new file mode 100644 index 00000000..ddcd334e --- /dev/null +++ b/arch/cortex-m23/m2351/src/NuBL2/FwInfo.c @@ -0,0 +1,88 @@ +/**************************************************************************//** + * @file FwInfo.c + * @version V1.00 + * @brief NuBL2 FW Info template and provided by NuBL2 developer. + * + * @copyright SPDX-License-Identifier: Apache-2.0 + * @copyright Copyright (C) 2017-2020 Nuvoton Technology Corp. All rights reserved. + ******************************************************************************/ +#include +#include +#include "NuMicro.h" +#include "NuBL2.h" + +#include "printf.h" + +/* + Description of FwInfo format: + [ Public key ] + Length: + Fixed 64 bytes. + Content: + ECC public key which will be updated according [KEY] Public Key 1 and Public Key 2 in the FwInfo.ini after executing FwSign.exe. + [ Metadata data ] + Length: + Fixed 4 words + 1 word Extend Info Length(N) + N words Extend Info Content. + Content: + Word-0, the ID Hash Configuration. + bit[1:0], reserved. + bit[2], indicates whether Info Hash includes PID hash, which will be updated according FwSign.ini after executing FwSign.exe. + If supports PID hash, add chip's PID to [PID] section in the FwInfo.ini as shown below example, + [PID] + PID=0x00235400 + bit[3], indicates whether Info Hash includes UID hash, which will be updated according FwSign.ini after executing FwSign.exe. + If supports UID hash, add chip's UID to [UID] section in the FwInfo.ini as shown below example, + [UID] + UID0=0x11111111 + UID1=0x22222222 + UID2=0x33333333 + bit[4], indicates whether Info Hash includes UCID hash, which will be updated according FwSign.ini after executing FwSign.exe. + If supports UCID hash, add chip's UCID to [UCID] section in the FwInfo.ini as shown below example, + [UCID] + UCID0=0xC1111111 + UCID1=0xC2222222 + UCID2=0xC3333333 + UCID3=0xC4444444 + bit[31:5], reserved. + Word-1, fixed 8(bytes) to indicate only NuBL2 FW region for secure boot verification. + Word-2, indicates the NuBL2 FW base address. + Word-3, indicates the NuBL2 FW size, which will be updated after NuBL2 is successfully built. + Word-4, indicates the valid Extend Info Length. Must be a word alignment length. + Word-5~, the content of Extend Info. + [ FW hash ] + Length: + Fixed 32 bytes. + Content: + To store the NuBL2 FW hash. + The target content will be updated according FW base and size in Metadata after executing FwSign.exe. + [ FwInfo signature ] + Length: + Fixed 64 bytes. + Content: + To store the ECDSA signature. + The target content will be updated according the ECC private key in FwSign.ini after executing FwSign.exe. +*/ +const uint32_t g_InitialFWInfo[] = +{ + /* Public key - 64-bytes (256-bits + 256-bits) */ + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + + /* Metadata data - includes ID Hash Configuration, FW region and Extend Info */ + 0x00000001, 0x00000008, 0x00000000, 0x00000000, // Word-2: 0x00000000, NuBL2 FW base + 0x0000000C, 0x20191201, 0x00000000, 0x00000000, // Word-5/6/7: 0x20191201/0x00000000/0x00000000, Extend Info + + /* FW hash - 32-bytes (256-bits) */ + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + + /* FwInfo signature - 64-bytes (256-bits R + 256-bits S) */ + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF +}; + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/arch/cortex-m23/m2351/src/NuBL2/NuBL2.h b/arch/cortex-m23/m2351/src/NuBL2/NuBL2.h new file mode 100644 index 00000000..a7b26a98 --- /dev/null +++ b/arch/cortex-m23/m2351/src/NuBL2/NuBL2.h @@ -0,0 +1,57 @@ +/**************************************************************************//** + * @file NuBL2.h + * @version V3.00 + * @brief NuBL2 header file. + * + * @copyright SPDX-License-Identifier: Apache-2.0 + * @copyright Copyright (C) 2017-2020 Nuvoton Technology Corp. All rights reserved. + ******************************************************************************/ +#include +#include +#include "NuMicro.h" + +#include "printf.h" + +#define NUBL32_FW_INFO_BASE 0x00038000ul // 224K +#define NUBL33_FW_INFO_BASE 0x10078000ul // 480K (Non-secure flash region) + + +typedef struct +{ + uint32_t u32Start; /* 32-bits */ + uint32_t u32Size; /* 32-bits */ +} __attribute__((packed)) FW_REGION_T; + +typedef struct +{ + uint32_t u32AuthCFGs; /* 32-bits */ + /* + bit[1:0]: Reserved + bit[2]: 1: Info Hash includes PDID / 0: Not include PDID + bit[3]: 1: Info Hash includes UID / 0: Not include UID + bit[4]: 1: Info Hash inculdes UCID / 0: Not include UCID + bit[31:5]: Reserved + */ + uint32_t u32FwRegionLen; /* 32-bits */ + FW_REGION_T au32FwRegion[1]; /* (8*1) bytes */ + uint32_t u32ExtInfoLen; /* 32-bits */ + uint32_t au32ExtInfo[3]; /* 12-bytes */ +} __attribute__((packed)) METADATA_T; + +typedef struct +{ + ECC_PUBKEY_T pubkey; /* 64-bytes (256-bits + 256-bits) */ + + METADATA_T mData; /* includes authenticate configuration, F/W regions and extend info */ + + uint32_t au32FwHash[8]; /* 32-bytes (256-bits) */ + + ECDSA_SIGN_T sign; /* 64-bytes (256-bits R + 256-bits S) */ +} __attribute__((packed)) FW_INFO_T; + + +int32_t VerifyNuBL3x(uint32_t *pu32FwInfo, uint32_t u32InfoBase); + +extern const uint32_t g_InitialFWInfo[]; // A global variable to store NuBL2 FWINFO address, declared in FwInfo.c + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/arch/cortex-m23/m2351/src/NuBL2/VerifyNuBL3x.c b/arch/cortex-m23/m2351/src/NuBL2/VerifyNuBL3x.c new file mode 100644 index 00000000..5e792f12 --- /dev/null +++ b/arch/cortex-m23/m2351/src/NuBL2/VerifyNuBL3x.c @@ -0,0 +1,402 @@ +/**************************************************************************//** + * @file VerifyNuBL3x.c + * @version V3.00 + * @brief This source file is used to authenticate the NuBL32 and NuBL33. + * + * @copyright SPDX-License-Identifier: Apache-2.0 + * @copyright Copyright (C) 2017-2020 Nuvoton Technology Corp. All rights reserved. + ******************************************************************************/ +#include +#include +#include "NuMicro.h" +#include "partition_M2351.h" +#include "NuBL2.h" + +// #define printf(...) + +#include "printf.h" + +#define DBG_EN 0 + +int32_t Cal_SHA256_Flash(uint32_t u32Addr, uint32_t u32Bytes, uint32_t *pu32Digest); +int32_t Cal_SHA256_SRAM(uint32_t u32Addr, uint32_t u32Bytes, uint32_t *pu32Digest); + +static void BytesSwap(char *buf, int32_t len) +{ + int32_t i; + char tmp; + + for(i = 0; i < (len / 2); i++) + { + tmp = buf[len - i - 1]; + buf[len - i - 1] = buf[i]; + buf[i] = tmp; + } +} + +int32_t Cal_SHA256_Flash(uint32_t u32Addr, uint32_t u32Bytes, uint32_t *pu32Digest) +{ + volatile int32_t i, bytes; + volatile uint32_t addr, data; + uint32_t u32TimeOutCnt; + + addr = u32Addr; + bytes = (int32_t)u32Bytes; + + /* Enable CRYPTO module clock */ + CLK->AHBCLK |= CLK_AHBCLK_CRPTCKEN_Msk; + + /* Reset CRYPTO module */ + SYS->IPRST0 |= SYS_IPRST0_CRPTRST_Msk; + SYS->IPRST0 &= ~SYS_IPRST0_CRPTRST_Msk; + + CRPT->HMAC_CTL = (SHA_MODE_SHA256 << CRPT_HMAC_CTL_OPMODE_Pos) | CRPT_HMAC_CTL_INSWAP_Msk | CRPT_HMAC_CTL_OUTSWAP_Msk; + CRPT->HMAC_DMACNT = 64; + CRPT->HMAC_CTL |= CRPT_HMAC_CTL_START_Msk; + + /* Start to calculate ... */ + while(bytes > 0) + { + if(bytes < 64) + CRPT->HMAC_DMACNT = (uint32_t)bytes; + + if(CRPT->HMAC_STS & CRPT_HMAC_STS_DATINREQ_Msk) + { + data = inpw(addr); + addr += 4; + bytes -= 4; + + if(bytes <= 0) + bytes = 0; + + /* bytes means remain byte counts */ + if(bytes != 0) + { + CRPT->HMAC_DATIN = data; + } + else + { + /* It's last word ... *-* */ + CRPT->HMAC_CTL |= CRPT_HMAC_CTL_START_Msk | CRPT_HMAC_CTL_DMALAST_Msk; + CRPT->HMAC_DATIN = data; + u32TimeOutCnt = SystemCoreClock; /* 1 second time-out */ + while(CRPT->HMAC_STS & CRPT_HMAC_STS_BUSY_Msk) + { + if(--u32TimeOutCnt == 0) + return -1; + } + + for(i=0; i<8; i++) + pu32Digest[i] = *(uint32_t *)((uint32_t) & (CRPT->HMAC_DGST[0]) + (uint32_t)(i * 4)); + } + } + } + +#if (DBG_EN == 1) // enable for debug + printf("Cal_SHA256_Flash\n"); + printf(" 0x%08x\n", pu32Digest[0]); + printf(" 0x%08x\n", pu32Digest[1]); + printf(" 0x%08x\n", pu32Digest[2]); + printf(" 0x%08x\n", pu32Digest[3]); + printf(" 0x%08x\n", pu32Digest[4]); + printf(" 0x%08x\n", pu32Digest[5]); + printf(" 0x%08x\n", pu32Digest[6]); + printf(" 0x%08x\n", pu32Digest[7]); +#endif + + return 0; +} + +int32_t Cal_SHA256_SRAM(uint32_t u32Addr, uint32_t u32Bytes, uint32_t *pu32Digest) +{ + uint32_t u32TimeOutCnt; + + /* Enable CRYPTO module clock */ + CLK_EnableModuleClock(CRPT_MODULE); + + /* Reset CRYPTO module */ + SYS_ResetModule(CRPT_MODULE); + + SHA_ENABLE_INT(CRPT); + + /*--------------------------------------- + * SHA-256 + *---------------------------------------*/ + XSHA_Open(XCRPT, SHA_MODE_SHA256, SHA_IN_OUT_SWAP, 0); + + XSHA_SetDMATransfer(XCRPT, u32Addr, u32Bytes); + + XSHA_Start(XCRPT, CRYPTO_DMA_ONE_SHOT); + u32TimeOutCnt = SystemCoreClock; /* 1 second time-out */ + while(SHA_GET_INT_FLAG(CRPT) == 0) + { + if(--u32TimeOutCnt == 0) + return -1; + } + SHA_CLR_INT_FLAG(CRPT); + + XSHA_Read(XCRPT, pu32Digest); + +#if (DBG_EN == 1) // enable for debug + printf("Cal_SHA256_SRAM\n"); + printf(" 0x%08x\n", pu32Digest[0]); + printf(" 0x%08x\n", pu32Digest[1]); + printf(" 0x%08x\n", pu32Digest[2]); + printf(" 0x%08x\n", pu32Digest[3]); + printf(" 0x%08x\n", pu32Digest[4]); + printf(" 0x%08x\n", pu32Digest[5]); + printf(" 0x%08x\n", pu32Digest[6]); + printf(" 0x%08x\n", pu32Digest[7]); +#endif + + return 0; +} + +static uint32_t *SetAES256Key(uint32_t *key) +{ +// AES: 1234567800000000000000000000000000000000000000000000000000accdef + key[0] = 0x12345678; + key[1] = 0x00000000; + key[2] = 0x00000000; + key[3] = 0x00000000; + key[4] = 0x00000000; + key[5] = 0x00000000; + key[6] = 0x00000000; + key[7] = 0x00accdef; + + return key; +} + +static uint32_t *SetAESIV(uint32_t *iv) +{ +// IV: 12345678000000000000000000accdef + iv[0] = 0x12345678; + iv[1] = 0x00000000; + iv[2] = 0x00000000; + iv[3] = 0x00accdef; + + return iv; +} + +static int32_t IdentifyNuBL3xPubKey(uint32_t *pu32FwInfo, uint32_t u32InfoBase) +{ + FW_INFO_T *pFwInfo; + ECC_PUBKEY_T PubKey; + uint32_t au32Hash0[8], au32Hash1[8], au32KeyBuf[8]; + uint32_t u32TimeOutCnt; + + if(u32InfoBase == NUBL32_FW_INFO_BASE) + { + /* Get encrypted NuBL32 public key and verify its hash value */ + extern uint32_t g_NuBL32KeyStart, g_NuBL32KeyEnd; // declared in NuBL3xKeyStorage.s + extern uint32_t g_NuBL32KeyHashStart, g_NuBL32KeyHashEnd; // declared in NuBL3xKeyStorage.s + memcpy((void *)&PubKey, (void *)&g_NuBL32KeyStart, ((uint32_t)&g_NuBL32KeyEnd-(uint32_t)&g_NuBL32KeyStart)); + memcpy((void *)&au32Hash0, (void *)&g_NuBL32KeyHashStart, ((uint32_t)&g_NuBL32KeyHashEnd-(uint32_t)&g_NuBL32KeyHashStart)); + } + else if (u32InfoBase == NUBL33_FW_INFO_BASE) + { + /* Get encrypted NuBL33 public key and verify its hash value */ + extern uint32_t g_NuBL33KeyStart, g_NuBL33KeyEnd; // declared in NuBL3xKeyStorage.s + extern uint32_t g_NuBL33KeyHashStart, g_NuBL33KeyHashEnd; // declared in NuBL3xKeyStorage.s + memcpy((void *)&PubKey, (void *)&g_NuBL33KeyStart, ((uint32_t)&g_NuBL33KeyEnd-(uint32_t)&g_NuBL33KeyStart)); + memcpy((void *)&au32Hash0, (void *)&g_NuBL33KeyHashStart, ((uint32_t)&g_NuBL33KeyHashEnd-(uint32_t)&g_NuBL33KeyHashStart)); + } + else + { + printf("\n\tInvalid F/W info base address.\n"); + return -1; + } + if(Cal_SHA256_SRAM((uint32_t)&PubKey, sizeof(ECC_PUBKEY_T), (uint32_t *)au32Hash1) != 0) + { + printf("\n\tWait for SHA time-out!\n"); + return -1; + } + if(memcmp(au32Hash0, au32Hash1, sizeof(au32Hash0)) != 0) + { + printf("\n\tVerify public key hash FAIL.\n"); + return -1; + } +#if (DBG_EN == 1) // enable for debug + printf("key, encrypted\n"); + printf(" 0x%08x\n", PubKey.au32Key0[0]); + printf(" 0x%08x\n", PubKey.au32Key0[1]); + printf(" 0x%08x\n", PubKey.au32Key0[2]); + printf(" 0x%08x\n", PubKey.au32Key0[3]); + printf(" 0x%08x\n", PubKey.au32Key0[4]); + printf(" 0x%08x\n", PubKey.au32Key0[5]); + printf(" 0x%08x\n", PubKey.au32Key0[6]); + printf(" 0x%08x\n", PubKey.au32Key0[7]); + printf(" 0x%08x\n", PubKey.au32Key1[0]); + printf(" 0x%08x\n", PubKey.au32Key1[1]); + printf(" 0x%08x\n", PubKey.au32Key1[2]); + printf(" 0x%08x\n", PubKey.au32Key1[3]); + printf(" 0x%08x\n", PubKey.au32Key1[4]); + printf(" 0x%08x\n", PubKey.au32Key1[5]); + printf(" 0x%08x\n", PubKey.au32Key1[6]); + printf(" 0x%08x\n", PubKey.au32Key1[7]); +#endif + + + /* Get NuBL3x F/W info */ + pFwInfo = (FW_INFO_T *)pu32FwInfo; + + + /* Decrypted NuBL3x public key and verify with F/W info */ + + /* Enable CRYPTO module clock */ + CLK_EnableModuleClock(CRPT_MODULE); + + AES_ENABLE_INT(CRPT); + + XAES_Open(XCRPT, 0, 0, AES_MODE_CFB, AES_KEY_SIZE_256, AES_IN_OUT_SWAP); + XAES_SetKey(XCRPT, 0, SetAES256Key(au32KeyBuf), AES_KEY_SIZE_256); + XAES_SetInitVect(XCRPT, 0, SetAESIV(au32KeyBuf)); + XAES_SetDMATransfer(XCRPT, 0, (uint32_t)&PubKey, (uint32_t)&PubKey, sizeof(ECC_PUBKEY_T)); + + XAES_Start(XCRPT, 0, CRYPTO_DMA_ONE_SHOT); + u32TimeOutCnt = SystemCoreClock; /* 1 second time-out */ + while(AES_GET_INT_FLAG(CRPT) == 0) + { + if(--u32TimeOutCnt == 0) + { + printf("\n\tWait for AES time-out!\n"); + return -1; + } + } + + AES_CLR_INT_FLAG(CRPT); +#if (DBG_EN == 1) // enable for debug + printf("key, decrypted\n"); + printf(" 0x%08x\n", PubKey.au32Key0[0]); + printf(" 0x%08x\n", PubKey.au32Key0[1]); + printf(" 0x%08x\n", PubKey.au32Key0[2]); + printf(" 0x%08x\n", PubKey.au32Key0[3]); + printf(" 0x%08x\n", PubKey.au32Key0[4]); + printf(" 0x%08x\n", PubKey.au32Key0[5]); + printf(" 0x%08x\n", PubKey.au32Key0[6]); + printf(" 0x%08x\n", PubKey.au32Key0[7]); + printf(" 0x%08x\n", PubKey.au32Key1[0]); + printf(" 0x%08x\n", PubKey.au32Key1[1]); + printf(" 0x%08x\n", PubKey.au32Key1[2]); + printf(" 0x%08x\n", PubKey.au32Key1[3]); + printf(" 0x%08x\n", PubKey.au32Key1[4]); + printf(" 0x%08x\n", PubKey.au32Key1[5]); + printf(" 0x%08x\n", PubKey.au32Key1[6]); + printf(" 0x%08x\n", PubKey.au32Key1[7]); +#endif + + if(memcmp((void *)&pFwInfo->pubkey.au32Key0[0], &PubKey, sizeof(ECC_PUBKEY_T)) != 0) + { + printf("\n\tCompare public key FAIL.\n"); + return -2; + } + + return 0; +} + +int32_t VerifyNuBL3x(uint32_t *pu32FwInfo, uint32_t u32InfoBase) +{ + FW_INFO_T *pFwInfo; + uint32_t u32Start, u32Size, au32Hash[8]; + uint32_t tmp[8]; + char m[65], Qx[65], Qy[65], R[65], S[65]; + + + /* Get NuBL3x F/W info */ + pFwInfo = (FW_INFO_T *)pu32FwInfo; + + /*---------------------------------------------------------------------------------------------------------*/ + /* Verify NuBL3x identity (check NuBL3x public key) */ + /*---------------------------------------------------------------------------------------------------------*/ + if(IdentifyNuBL3xPubKey((uint32_t *)(uint32_t)pFwInfo, u32InfoBase) < 0) + { + printf("\n\tIdentify F/W public key FAIL!!\n"); + return -1; + } + else + { + printf("\nIdentify F/W public key PASS.\n"); + } + + + /*---------------------------------------------------------------------------------------------------------*/ + /* Verify NuBL3x F/W info ECDSA signature */ + /*---------------------------------------------------------------------------------------------------------*/ + /* Calculate message (NuBL3x F/W info hash) */ + u32Start = (uint32_t)pFwInfo; + u32Size = sizeof(FW_INFO_T) - sizeof(ECDSA_SIGN_T); + if(Cal_SHA256_SRAM(u32Start, u32Size, (uint32_t *)au32Hash) != 0) + { + printf("\n\tWait for SHA time-out!\n"); + return -1; + } + memcpy((void*)tmp, (uint32_t *)au32Hash, sizeof(tmp)); + BytesSwap((char*)tmp, sizeof(tmp)); + XECC_Reg2Hex(64, tmp, m); + + /* Get Qx */ + memcpy((void*)tmp, (uint32_t *)pFwInfo->pubkey.au32Key0, sizeof(tmp)); + BytesSwap((char*)tmp, sizeof(tmp)); + XECC_Reg2Hex(64, tmp, Qx); + + /* Get Qy */ + memcpy((void*)tmp, (uint32_t *)pFwInfo->pubkey.au32Key1, sizeof(tmp)); + BytesSwap((char*)tmp, sizeof(tmp)); + XECC_Reg2Hex(64, tmp, Qy); + + /* Get R */ + memcpy((void*)tmp, (uint32_t *)pFwInfo->sign.au32R, sizeof(tmp)); + BytesSwap((char*)tmp, sizeof(tmp)); + XECC_Reg2Hex(64, tmp, R); + + /* Get S */ + memcpy((void*)tmp, (uint32_t *)pFwInfo->sign.au32S, sizeof(tmp)); + BytesSwap((char*)tmp, sizeof(tmp)); + XECC_Reg2Hex(64, tmp, S); + +#if (DBG_EN == 1) // enable for debug + printf("Input:\n"); + printf(" m\t%s\n", m); + printf(" Qx\t%s\n", Qx); + printf(" Qy\t%s\n", Qy); + printf(" R\t%s\n", R); + printf(" S\t%s\n", S); +#endif + + ECC_ENABLE_INT(CRPT); + if(XECC_VerifySignature(XCRPT, CURVE_P_256, m, Qx, Qy, R, S) < 0) + { + printf("\n\tF/W info ECDSA signature verification FAIL!!\n"); + return -1; + } + else + { + printf("\nF/W info ECDSA signature verification PASS.\n"); + } + + + /*---------------------------------------------------------------------------------------------------------*/ + /* Verify NuBL3x F/W integrity */ + /*---------------------------------------------------------------------------------------------------------*/ + /* Calculate F/W hash */ + u32Start = (uint32_t)pFwInfo->mData.au32FwRegion[0].u32Start; + u32Size = (uint32_t)pFwInfo->mData.au32FwRegion[0].u32Size; + if(Cal_SHA256_Flash(u32Start, u32Size, (uint32_t *)au32Hash) != 0) + { + printf("\n\tWait for SHA time-out!\n"); + return -1; + } + if(memcmp((void*)&pFwInfo->au32FwHash[0], au32Hash, sizeof(au32Hash)) != 0) + { + printf("\n\tVerify F/W hash integrity FAIL.\n"); + return -1; + } + else + { + printf("\nVerify F/W hash integrity PASS.\n\n"); + } + + return 0UL; +} + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/arch/cortex-m23/m2351/src/NuBL2/main.c b/arch/cortex-m23/m2351/src/NuBL2/main.c new file mode 100644 index 00000000..f5d40777 --- /dev/null +++ b/arch/cortex-m23/m2351/src/NuBL2/main.c @@ -0,0 +1,294 @@ +/**************************************************************************//** + * @file main.c + * @version V3.00 + * @brief Demonstrate how to generate a boot image(NuBL2) and can be authenticated by Secure Bootloader(NuBL1). + * After NuBL2 runs, NuBL2 will authenticate NuBL32 and NuBL33 then jump to execute in NuBL32. + * + * @copyright SPDX-License-Identifier: Apache-2.0 + * @copyright Copyright (C) 2017-2020 Nuvoton Technology Corp. All rights reserved. + ******************************************************************************/ +#include +#include +#include "NuMicro.h" +#include "NuBL2.h" + +#include "printf.h" + +#define SET_SECURE_BOOT (0) // Set 1 to support modify CFG0[5] MBS 0 for booting from Secure Bootloader +#define ENABLE_XOM0_REGION (0) // Set 1 to configure VerifyNuBL3x.c code in XOM0 region, and cannot trace VerifyNuBL3x.c flow in ICE debug mode + + +static volatile FW_INFO_T s_NuBL3xFwInfo; // Allocate a FWINFO buffer for storing NuBL32/NuBL33 FWINFO data + +int32_t EnableXOM0(void); +void SYS_Init(void); +void UART_Init(void); + +/*---------------------------------------------------------------------------------------------------------*/ +/* Check Booting status and show F/W info data */ +/*---------------------------------------------------------------------------------------------------------*/ +static int32_t CheckBootingStatus(void) +{ + uint32_t i; + uint32_t u32CFG0, au32OTP[8]; + uint32_t *pu32Info, u32Size; + + /* Unlock protected registers */ + SYS_UnlockReg(); + + /* Enable FMC ISP function */ + FMC_ENABLE_ISP(); + + u32CFG0 = FMC_Read(FMC_USER_CONFIG_0); + printf("Current CFG0: 0x%x.\n\n", u32CFG0); + + if((u32CFG0&BIT5) == BIT5) + { + printf("Device is booting from %s. NOT booting from Secure Bootloader(NuBL1).\n\n", + FMC_GetBootSource()==0?"APROM":"LDROM"); + +#if (SET_SECURE_BOOT == 1) // enable to configure booting from Secure Bootloader + { + char ch; + printf("Hit [S/s] to configure booting from Secure Bootloader(NuBL1).\n\n"); + ch = GetChar(); + if((ch == 's') || (ch == 'S')) + { + FMC_ENABLE_CFG_UPDATE(); + FMC_Write(FMC_USER_CONFIG_0, (u32CFG0&~BIT5)); + + /* Reset chip to enable booting from Secure Bootloader. */ + SYS_ResetChip(); + while(1) {}; + } + } +#endif + + return -1; + } + + printf("[Device is successfully booting from Secure Bootloader(NuBL1) and device PID is 0x%08x]\n\n", FMC_ReadPID()); + + /* + Notes of NuBL2 ECC public key and its SHA-256 Key hash: + * Public Key 1 = 755B3819F05A3E9F32D4D599062834AAC5220F75955378414A8F63716A152CE2 + Public Key 2 = 91C413F1915ED7B47473FD797647BA3D83E8224377909AF5B30C530EAAD79FD7 + * The Key hash = 145e73e48865222fa4d9741671c0c670ed45fe06b24cdb5dd507d7ab35ee9363 + * Stored in M2351 OTP0~3 for identification in secure boot are: + Index Low word High word + -------------------------------------- + OTP0: 0xe4735e14, 0x2f226588 + OTP1: 0x1674d9a4, 0x70c6c071 + OTP2: 0x06fe45ed, 0x5ddb4cb2 + OTP3: 0xabd707d5, 0x6393ee35 + */ + + /* Read NuBL2 ECC public key hash */ + FMC_Read_OTP(0, &au32OTP[0], &au32OTP[1]); + FMC_Read_OTP(1, &au32OTP[2], &au32OTP[3]); + FMC_Read_OTP(2, &au32OTP[4], &au32OTP[5]); + FMC_Read_OTP(3, &au32OTP[6], &au32OTP[7]); + printf("NuBL2 ECC public key hash are:\n"); + for(i=0; i<8; i++) + { + printf(" 0x%08x\n", au32OTP[i]); + } + printf("\n"); + + + /* Show NuBL2 F/W info data */ + pu32Info = (uint32_t *)(uint32_t)g_InitialFWInfo; + u32Size = sizeof(FW_INFO_T); + + printf("NuBL2 F/W info in 0x%08x.\nData are:\n", (uint32_t)pu32Info); + for(i=0; i<(u32Size/4); i+=4) + { + printf(" 0x%08x", pu32Info[i+0]); + printf(" 0x%08x", pu32Info[i+1]); + printf(" 0x%08x", pu32Info[i+2]); + printf(" 0x%08x", pu32Info[i+3]); + printf("\n"); + } + printf("\n"); + + return 0; +} + +int32_t EnableXOM0(void) +{ + int32_t i32Status; + uint32_t u32Base = 0x10000; + uint8_t u8Page = 4; + + /* Unlock protected registers */ + SYS_UnlockReg(); + + /* Enable FMC ISP function and enable APROM active */ + FMC_ENABLE_ISP(); + FMC_ENABLE_AP_UPDATE(); + + if((FMC->XOMSTS & 0x1) != 0x1) + { + printf("\nXOM0 base: 0x%x, page count: %d.\n\n", u32Base, u8Page); + + if(FMC_GetXOMState(XOMR0) == 0) + { + i32Status = FMC_ConfigXOM(XOMR0, u32Base, u8Page); + if(i32Status == 0) + { + printf("Configure XOM0 Success.\n"); + } + else + { + printf("Configure XOM0 FAIL.\n"); + return -1; + } + } + else + { + printf("Get XOM0 status FAIL.\n\n"); + return -1; + } + + printf("Reset chip to enable XOM region.\n\n"); + UART_WAIT_TX_EMPTY((UART_T *)DEBUG_PORT); + + /* Reset chip to enable XOM region. */ + SYS_ResetChip(); + while(1) {} + } + else + { + printf("XOM0 region is already actived.\n\n"); + } + + return 0; +} + +void SYS_Init(void) +{ + /*---------------------------------------------------------------------------------------------------------*/ + /* Init System Clock */ + /*---------------------------------------------------------------------------------------------------------*/ + /* Enable HIRC clock */ + CLK_EnableXtalRC(CLK_PWRCTL_HIRCEN_Msk); + + /* Waiting for HIRC clock ready */ + CLK_WaitClockReady(CLK_STATUS_HIRCSTB_Msk); + + /* Switch HCLK clock source to HIRC */ + CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_HIRC, CLK_CLKDIV0_HCLK(1)); + + /* Enable PLL */ + CLK->PLLCTL = CLK_PLLCTL_128MHz_HIRC; + + /* Waiting for PLL stable */ + CLK_WaitClockReady(CLK_STATUS_PLLSTB_Msk); + + /* Select HCLK clock source as PLL and HCLK source divider as 2 */ + CLK_SetHCLK(CLK_CLKSEL0_HCLKSEL_PLL, CLK_CLKDIV0_HCLK(2)); + + /* Set SysTick source to HCLK/2*/ + CLK_SetSysTickClockSrc(CLK_CLKSEL0_STCLKSEL_HCLK_DIV2); + + /* Enable UART module clock */ + CLK_EnableModuleClock(UART0_MODULE); + CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL1_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1)); + + /*---------------------------------------------------------------------------------------------------------*/ + /* Init I/O Multi-function */ + /*---------------------------------------------------------------------------------------------------------*/ + /* Set multi-function pins for UART0 RXD and TXD */ + SYS->GPB_MFPH = (SYS->GPB_MFPH & (~(UART0_RXD_PB12_Msk | UART0_TXD_PB13_Msk))) | UART0_RXD_PB12 | UART0_TXD_PB13; +} + +void UART_Init(void) +{ + /*---------------------------------------------------------------------------------------------------------*/ + /* Init UART */ + /*---------------------------------------------------------------------------------------------------------*/ + /* Reset UART module */ + SYS_ResetModule(UART0_RST); + + /* Configure UART and set UART Baudrate */ + UART_Open((UART_T *)DEBUG_PORT, 115200); +} + +/*---------------------------------------------------------------------------------------------------------*/ +/* MAIN function */ +/*---------------------------------------------------------------------------------------------------------*/ +int main(void) +{ + uint32_t u32NuBL32Base, u32TimeOutCnt; + + /* Unlock protected registers */ + SYS_UnlockReg(); + + /* Init System, peripheral clock and multi-function I/O */ + SYS_Init(); + + /* Init UART for printf */ + UART_Init(); + + printf("\n\nCPU @ %d Hz (Non-secure flash base: 0x%x)\n", SystemCoreClock, BL_GetNSBoundary()); + printf("+------------------------------------------+\n"); + printf("| SecureBootDemo - NuBL2 Sample Code |\n"); + printf("+------------------------------------------+\n\n"); + + /* Show booting status */ + CheckBootingStatus(); + +#if (ENABLE_XOM0_REGION == 1) + + /* Enable XOM0, and all the functions in VerifyNuBL3x.c cannot trace in ICE debug mode */ + if( EnableXOM0() < 0 ) goto lexit; +#endif + + /* Verify NuBL32 identity and F/W integrity */ + memcpy((void *)(uint32_t)&s_NuBL3xFwInfo, (void *)NUBL32_FW_INFO_BASE, sizeof(FW_INFO_T)); + if(VerifyNuBL3x((uint32_t *)(uint32_t)&s_NuBL3xFwInfo, NUBL32_FW_INFO_BASE) == -1) + { + printf("\n\nNuBL2 verifies NuBL32 FAIL.\n"); + goto lexit; + } + else + { + u32NuBL32Base = s_NuBL3xFwInfo.mData.au32FwRegion[0].u32Start; + printf("\nNuBL2 identify NuBL32 public key and verify NuBL32 F/W integrity PASS.\n"); + } + + + /* Verify NuBL33 identity and F/W integrity */ + memcpy((void *)(uint32_t)&s_NuBL3xFwInfo, (void *)NUBL33_FW_INFO_BASE, sizeof(FW_INFO_T)); + if(VerifyNuBL3x((uint32_t *)(uint32_t)&s_NuBL3xFwInfo, NUBL33_FW_INFO_BASE) == -1) + { + printf("\n\nNuBL2 verifies NuBL33 FAIL.\n"); + goto lexit; + } + else + { + printf("\nNuBL2 identify NuBL33 public key and verify NuBL33 F/W integrity PASS.\n"); + } + + + /* Jump to execute NuBL32 F/W */ + printf("\nJump to execute NuBL32...\n"); + u32TimeOutCnt = SystemCoreClock; /* 1 second time-out */ + UART_WAIT_TX_EMPTY((UART_T *)DEBUG_PORT) + if(--u32TimeOutCnt == 0) break; + + /* Disable all interrupt */ + __set_PRIMASK(1); + + FMC_ENABLE_ISP(); + FMC_SetVectorPageAddr(u32NuBL32Base); + + /* Reset CPU only to reset to new vector page */ + SYS->IPRST0 |= SYS_IPRST0_CPURST_Msk; + +lexit: + + while(1) {} +} + +/*** (C) COPYRIGHT 2018 Nuvoton Technology Corp. ***/ diff --git a/docs/build.md b/docs/build.md index 242e80d1..9161b8d9 100644 --- a/docs/build.md +++ b/docs/build.md @@ -114,25 +114,6 @@ cd mTower/ make PLATFORM=numaker_pfm_m2351 create_context ``` -To use BootLoader2 for M2351 Nuvoton chips, you need to download NuBL2 sources. This can be done by executing following shell commands: - -```sh -wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/main.c -O ./arch/cortex-m23/m2351/src/NuBL2/main.c -``` -```sh -wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/VerifyNuBL3x.c -O ./arch/cortex-m23/m2351/src/NuBL2/VerifyNuBL3x.c -``` -```sh -wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/NuBL2.h -O ./arch/cortex-m23/m2351/src/NuBL2/NuBL2.h -``` -```sh -wget -L https://raw.githubusercontent.com/OpenNuvoton/M2351BSP/master/SampleCode/MKROM/SecureBootDemo/NuBL2/FwInfo/FwInfo.c -O ./arch/cortex-m23/m2351/src/NuBL2/FwInfo.c -``` - -> Please note that files from these downloads contain the following copyright -notice: `Copyright (C) 2017 Nuvoton Technology Corp. All rights reserved.` -Licensing terms specified [here](https://github.com/OpenNuvoton/M2351BSP/blob/master/NUVOTON%20SOFTWARE%20LICENSE%20AGREEMENT.pdf). - ### 2.4 Get the toolchains In mTower different toolchains are used for different targets (depends on architecture 32-bit solutions). In any case start by downloading the diff --git a/tools/fwinfogen.c b/tools/fwinfogen.c index 7422420d..d0bc3072 100644 --- a/tools/fwinfogen.c +++ b/tools/fwinfogen.c @@ -147,7 +147,7 @@ typedef struct { /* Public Data. */ /* All data definitions with global scope appear here. */ const char header[] = "\n" - "const uint32_t g_InitialFWinfo[] =\n" + "const uint32_t g_InitialFWInfo[] =\n" "{\n" " /* public key - 64-bytes (256-bits + 256-bits) */\n";