4.2 Adding the Secure Application Logic

To develop and run the application, follow these steps:

  1. Declare the following variables and macros used by the secure application in the main.c file.
    #include <string.h>
    #include "non_secure_app_image_pic32cm_ls00_cnano.h"
    
    #define APP_IMAGE_SIZE          sizeof(image_pattern)
    #define APP_IMAGE_END_ADDR      (APP_IMAGE_START_ADDR + APP_IMAGE_SIZE)
    #define NON_SECURE_APP_ADDR     (TZ_START_NS)
    
    static uint8_t *appStart = (uint8_t *)NON_SECURE_APP_ADDR;
    static uint8_t *dataStart = (uint8_t *)NVMCTRL_DATAFLASH_START_ADDRESS;
    
    uint8_t firmware_digest_0[64];
    uint8_t firmware_digest_1[32];
    
    Figure 4-7. Declaration of Variables and Macros
  2. Add the Boot ROM APIs in the main.c file to access them as follows.
    typedef struct 
    {
        /* Digest result of SHA256 */
        uint32_t digest[8];
        /* Length of the message */
        uint64_t length;
        /* Holds the size of the remaining part of data */
        uint32_t remain_size;
        /* Buffer of remaining part of data (512 bits data block) */
        uint8_t remain_ram[64];
        /* RAM buffer of 256 bytes used by crya_sha_process */
        uint32_t process_buf[64];
        
    } SHA256_CTX;
    
    SHA256_CTX sha256_ctx;
    
    typedef void (*crya_sha256_init_t) (SHA256_CTX *context);
    typedef void (*crya_sha256_update_t) (SHA256_CTX *context, const unsigned char *data, size_t length);
    typedef void (*crya_sha256_final_t) (SHA256_CTX *context, unsigned char output[32]);
    
    #define crya_sha256_init ((crya_sha256_init_t) (0x02006810 | 0x1))
    #define crya_sha256_update ((crya_sha256_update_t) (0x02006814 | 0x1))
    #define crya_sha256_final ((crya_sha256_final_t) (0x02006818 | 0x1))
    
  3. Include the flash_write API in the main.c file to program the Non-Secure firmware in the Non-Secure Flash region and write the firmware digest in the Secure Data Flash.
    static void flash_write(uint32_t addr, uint8_t *buf, uint32_t size)
    {      
        uint32_t end_addr = addr + size;
        
        if((addr & NVMCTRL_DATAFLASH_START_ADDRESS) == NVMCTRL_DATAFLASH_START_ADDRESS)
        {
            /* Unlock the Secure Data Flash region */
            NVMCTRL_RegionUnlock(NVMCTRL_SECURE_MEMORY_REGION_DATA);
            while(NVMCTRL_IsBusy());
        }
        
        else
        {
            /* Unlock the Non-Secure Flash region */
            NVMCTRL_RegionUnlock(NVMCTRL_MEMORY_REGION_APPLICATION);
            while(NVMCTRL_IsBusy());
        }    
    
        do
        {
            if(addr % NVMCTRL_FLASH_ROWSIZE == 0)
            {
                /* Erase the row */
                NVMCTRL_RowErase(addr);
                while(NVMCTRL_IsBusy());
            }
    
            /* Program 64 byte page */
            NVMCTRL_PageWrite((uint32_t *)(buf), addr);
            while(NVMCTRL_IsBusy());
            
            addr += NVMCTRL_FLASH_PAGESIZE;
            buf += NVMCTRL_FLASH_PAGESIZE;
            
        }while (addr < end_addr);     
    }
    
  4. Add the SHA-256 Hash and Non-Secure firmware verification API to the main.c file for calculating the Non-Secure firmware digest.
    static void sha256_hash(SHA256_CTX *ctx, const uint8_t *message, uint32_t length, 
            unsigned char digest[32])
    {
        uint8_t dataBuf[64];
        
        uint32_t bufIdx = 0;
        
        crya_sha256_init(ctx);
        
        do
        {     
            memcpy(dataBuf, &message[bufIdx], 64);
            
            crya_sha256_update(ctx, dataBuf, sizeof(dataBuf));
            bufIdx += 64;
            
        }while (bufIdx < APP_IMAGE_SIZE);
    
        crya_sha256_final(ctx, digest);
    }
    static bool non_secure_app_verify(void)
    {    
        sha256_hash(&sha256_ctx, appStart, APP_IMAGE_SIZE, firmware_digest_1);
    
        if(memcmp(dataStart, firmware_digest_1, 32) != 0) 
        {        
            printf("Firmware is Corrupted....!");
            printf("\n\r\n\r");
            
            printf("Firmware Digest after tamper detection:");
            printf("\n\r\n\r");
    
            for(int i=0; i<32; i++)
            {
                printf("0x%X ", dataStart[i]);
    
                if((i%8 == 0) && (i != 0))
                {
                    printf("\n\r");
                }
            }        
            flash_write(TZ_START_NS, (uint8_t *)&image_pattern, sizeof(image_pattern));
            
            sha256_hash(&sha256_ctx, image_pattern, APP_IMAGE_SIZE, firmware_digest_1);
            
            printf("\n\r\n\r");
            printf("Restored Firmware Digest:");      
            printf("\n\r\n\r");
    
            for(int i=0; i<32; i++)
            {
                printf("0x%X ", firmware_digest_1[i]);
    
                if((i%8 == 0) && (i != 0))
                {
                    printf("\n\r");
                }
            }
            printf("\n\r\n\r");
            printf("Genuine Firmware is restored");
    
        }
        else
        {        
            return false;
        }
        
        return true;
    }
  5. Include the RTC Callback in the main.c for the tamper interrupt and 30-second timeout.
    void timeout_handler(RTC_TIMER32_INT_MASK intCause, uintptr_t context)
    {
        if(RTC_TIMER32_INT_MASK_CMP0  == (RTC_TIMER32_INT_MASK_CMP0 & intCause ))
        {
            if(non_secure_app_verify() == true)
            {
                SYSTICK_DelayMs(2000);
    
                NVIC_SystemReset();
            }
        }
    
        if (RTC_TIMER32_INT_MASK_TAMPER == (intCause & RTC_TIMER32_INT_MASK_TAMPER))
        {        
            RTC_REGS->MODE2.RTC_TAMPID = RTC_TAMPID_Msk;
             
            printf("Software Attack Detected");        
            printf("\n\r\n\r");
        }
    }
  6. Add the following code snippets after the SYS_Initialize API in the main.c.
    sha256_hash(&sha256_ctx, image_pattern, APP_IMAGE_SIZE, firmware_digest_0);
        
    flash_write(NVMCTRL_DATAFLASH_START_ADDRESS, firmware_digest_0, sizeof(firmware_digest_0));
    
    Note:
    • sha256_hash: Calculates the digest of the Non-Secure Firmware.
    • flash_write: Stores the firmware digest in the Secure Data Flash region.
    SYSTICK_TimerStart();
                
        RTC_Timer32CallbackRegister(timeout_handler,0);
        RTC_Timer32Start();
        printf("\n\r---------------------------------------------------------");
        printf("\n\r           Software Attack Protection Demo               ");
        printf("\n\r---------------------------------------------------------\n\r");
          
        if(non_secure_app_verify() != true)
        {
            printf("\n\rFirmware is Genuine");
            printf("\n\r\n\r");
        }
    
    Note:
    • non_secure_app_verify: Verify the Non-Secure firmware and program the genuine copy in the Non-Secure Flash region if the verification fails.