FreeCalypso > hg > tcs211-l1-reconst
view g23m/condat/com/src/comlib/sec_drv_prim.c @ 0:509db1a7b7b8
initial import: leo2moko-r1
author | Space Falcon <falcon@ivan.Harhan.ORG> |
---|---|
date | Mon, 01 Jun 2015 03:24:05 +0000 |
parents | |
children |
line wrap: on
line source
#include "general.h" #include "typedefs.h" #include "vsi.h" #include <stdlib.h> #include <string.h> #include "sec_drv.h" #include "sec_drv_prim.h" #include "ffs/ffs.h" #ifndef NON_ENCRYPTED_MODE #include "cl_des.h" #include "cl_imei.h" #endif /* Layout of flash: T_SEC_DRV_GLOBAL_CONF T_SEC_DRV_KEY (failure count) T_SEC_DRV_CONFIGURATION { T_SEC_DRV_KEY T_SEC_DRV_CATEGORY (T_SEC_DRV_CAT_HDR + SEC_DRV_CAT_MAX_SIZE*UINT8) }[configuration -> number of categories] */ /******************************************* Global variables *******************************************/ #ifndef FFS_MODE_ENABLED /* SIM lock data area in flash */ #pragma DATA_SECTION(d_mepd_data, ".mepd") volatile const UINT8 d_mepd_data; // Adress of first byte in 8 kb buffer #endif /* FFS_MODE_ENABLED */ static T_SEC_DRV_GLOBAL_CONF gGlobalConf; static INT8 gGlobalConfRead = FALSE; INT8 sec_drv_fast_write = FALSE; static INT16 gMaxCategories = 0; #if (defined(RSA_HEAP_IS_INTERNAL) && defined(FIRSTBOOT_RSA_ENABLED)) || (defined(USE_RSAHEAP_FOR_FLASH) && !defined(FFS_MODE_ENABLED)) #ifdef USE_RSAHEAP_FOR_FLASH char sec_drv_buffer[SEC_FLASH_SIZE]; #else /* USE_RSAHEAP_FOR_FLASH */ char sec_drv_buffer[RSA_HEAP_SIZE]; #endif /* USE_RSAHEAP_FOR_FLASH */ #endif /******************************************* Trace functionality *******************************************/ #ifdef SEC_TRACES_ENABLED static void _trace(const char *str) { T_FFS_FD test_file; test_file = ffs_open("/testfile.txt", FFS_O_CREATE | FFS_O_WRONLY | FFS_O_APPEND); if (test_file > 0) { ffs_write(test_file, (char *)str, strlen((char *)str)); ffs_close(test_file); } } void test_trace(const char *str) { char *s = (char *)str; T_FFS_FD test_file; test_file = ffs_open("/testfile.txt", FFS_O_CREATE | FFS_O_WRONLY | FFS_O_APPEND); if (test_file > 0) { ffs_write(test_file, s, strlen(s)); s = "\n"; ffs_write(test_file, s, strlen(s)); ffs_close(test_file); } } void hex_trace(const char *str, const void *in, unsigned long int size) { char buffer[4]; unsigned long int i; _trace(str); for (i=0; i<size; i++) { sprintf(buffer, "%02x ", ((volatile unsigned char *)in)[i]); _trace(buffer); } _trace("\n"); } #endif /* SEC_TRACES_ENABLED */ #ifdef FFS_MODE_ENABLED /******************************************* FFS functions *******************************************/ void sec_drv_flash_backup(void) { } void sec_drv_remove_backup(void) { } void sec_drv_erase_flash(void) { } void sec_drv_read_flash(UINT32 offset, void *pDest, UINT32 size) { T_FFS_FD file; file = ffs_open(FFS_MEPD_FILENAME, FFS_O_RDONLY); if (file <= 0) { memset(pDest, 0, size); TRACE("sec_drv_read_flash - FAILed opening file!"); } else { ffs_seek(file, offset, FFS_SEEK_SET); ffs_read(file, pDest, size); ffs_close(file); } } void sec_drv_write_flash(UINT32 offset, const void *pSrc, UINT32 size) { T_FFS_FD file; file = ffs_open(FFS_MEPD_FILENAME, FFS_O_WRONLY ); if (!(file <= 0)) { ffs_seek(file, offset, FFS_SEEK_SET); ffs_write(file, (void *)pSrc, size); ffs_close(file); } else { TRACE("sec_drv_write_flash - FAILed opening file!"); } } #else /* FFS_MODE_ENABLED */ /******************************************* Memory functions *******************************************/ UINT32 gBackupOffset; void sec_drv_flash_backup(void) { if (!sec_drv_fast_write) { TRACE("sec_drv_flash_backup"); #ifdef USE_RSAHEAP_FOR_FLASH sec_drv_read_flash(0, (void *)SEC_DRV_RSA_HEAP, SEC_FLASH_SIZE); #else /* USE_RSAHEAP_FOR_FLASH */ #error "QUESTION: what if we don't have the space required?" T_FFS_FD file = ffs_open(FLASH_BACKUP_NAME, FFS_O_CREATE | FFS_O_WRONLY | FFS_O_TRUNC); ffs_write(file, (void *)SEC_BASE, SEC_FLASH_SIZE); ffs_close(file); #endif /* USE_RSAHEAP_FOR_FLASH */ gBackupOffset = 0; } } void sec_drv_remove_backup(void) { if (!sec_drv_fast_write) { #ifdef USE_RSAHEAP_FOR_FLASH copy_to_flash(0, 0, 0, gBackupOffset, SEC_FLASH_SIZE); TRACE("sec_drv_remove_backup"); memset(SEC_DRV_RSA_HEAP, 0xFF, SEC_FLASH_SIZE); #else /* USE_RSAHEAP_FOR_FLASH */ #error "QUESTION: what if we don't have the space required?" T_FFS_FD file; void *buf; TRACE("sec_drv_remove_backup"); buf = M_ALLOC(BACKUP_BUF_SIZE); file = ffs_open(FLASH_BACKUP_NAME, FFS_O_RDONLY); copy_to_flash(file, buf, BACKUP_BUF_SIZE, gBackupOffset, SEC_FLASH_SIZE); ffs_close(file); M_FREE(buf); ffs_remove(FLASH_BACKUP_NAME); #endif /* USE_RSAHEAP_FOR_FLASH */ } } void sec_drv_erase_flash(void) { if (!sec_drv_fast_write) { TRACE("sec_drv_erase_flash"); sec_drv_amd_erase(); } } void sec_drv_read_flash(UINT32 offset, void *pDest, UINT32 size) { void *pSrc = (void *)((UINT32)SEC_BASE + offset); assert(pSrc != 0L); assert(pDest != 0L); assert(size > 0L); assert(offset >= 0L && (offset+size) <= SEC_FLASH_SIZE); memcpy(pDest, pSrc, size); } static void copy_to_flash(T_FFS_FD file, void *pBuf, UINT32 bufSize, UINT32 offset, UINT32 maxOffset) { UINT32 size = maxOffset-offset; TRACE("copy_to_flash"); #ifdef USE_RSAHEAP_FOR_FLASH sec_drv_amd_write((void *)((UINT32)SEC_BASE+offset), (const void *)((UINT32)SEC_DRV_RSA_HEAP+offset), size); #else /* USE_RSAHEAP_FOR_FLASH */ ffs_seek(file, offset, FFS_SEEK_SET); while(offset < maxOffset) { size = (maxOffset-offset > bufSize)? bufSize : maxOffset-offset; ffs_read(file, pBuf, size); sec_drv_amd_write((void *)(SEC_BASE + offset), pBuf, size); offset += size; } #endif /* USE_RSAHEAP_FOR_FLASH */ } void sec_drv_write_flash(UINT32 offset, const void *pSrc, UINT32 size) { assert(pSrc != 0L); assert(size > 0L); assert(offset >= 0L && (offset+size) <= SEC_FLASH_SIZE); if (sec_drv_fast_write) { TRACE("sec_drv_write_flash"); sec_drv_amd_write((void *)((UINT32)SEC_BASE+offset), pSrc, size); } else { #ifdef USE_RSAHEAP_FOR_FLASH copy_to_flash(0, 0, 0, gBackupOffset, offset); HEXTRACE("sec_drv_write_flash - offset: ", &offset, sizeof(UINT32)); sec_drv_amd_write((void *)((UINT32)SEC_BASE+offset), pSrc, size); gBackupOffset = offset+size; #else /* USE_RSAHEAP_FOR_FLASH */ T_FFS_FD file; void *buf; TRACE("Using FFS"); buf = M_ALLOC(BACKUP_BUF_SIZE); file = ffs_open(FLASH_BACKUP_NAME, FFS_O_RDONLY); copy_to_flash(file, buf, BACKUP_BUF_SIZE, gBackupOffset, offset); sec_drv_amd_write((void *)((UINT32)SEC_BASE + offset), pSrc, size); gBackupOffset += size; ffs_close(file); M_FREE(buf); #endif /* USE_RSAHEAP_FOR_FLASH */ } } #endif /* FFS_MODE_ENABLED */ /******************************************* DES de-/encryption *******************************************/ /** * Returns the DES key from the DSP * * @return The DES key for use by de-encryption */ static const UINT8 *GetDESKey(void) { #ifdef DSP_DES_KEY_ENABLED #error "Not yet implemented" #else /* DSP_DES_KEY_ENABLED */ static const UINT8 desKey[8] = {0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78}; #ifndef NON_ENCRYPTED_MODE #ifdef CL_IMEI_CALYPSO_PLATFORM #ifdef FF_PROTECTED_IMEI volatile USHORT *reg_p = (USHORT *) CL_IMEI_DIE_ID_REG; USHORT *outBuf16 = (USHORT*)&desKey[0]; INT8 i; for (i = 0; i < CL_IMEI_DIE_ID_SIZE; i++) { /* Die ID is 4 BYTE long, extract it to 8 BYTE. */ outBuf16[i] = (USHORT)(*(UINT8*)(reg_p)++); } #endif #endif #endif return desKey; #endif /* DSP_DES_KEY_ENABLED */ } /** * Read a crypted block of the secure_area. * * @param offset Offset into the secure area from which to read the block. * @param pDest Pointer to the receiving buffer. * @param size Size of the block to read. Minimum 1. */ static void read_crypted_flash(UINT32 offset, void *pDest, UINT32 size) { #ifndef NON_ENCRYPTED_MODE UINT8 inbuffer[CRYPT_BLOCK_SIZE]; UINT8 outbuffer[CRYPT_BLOCK_SIZE]; #endif UINT32 blocksize; assert(offset != 0L); assert(pDest != 0L); assert(size > 0L); assert(offset >= 0L && (offset+size) <= SEC_FLASH_SIZE); do { blocksize = (size>CRYPT_BLOCK_SIZE)? CRYPT_BLOCK_SIZE : size; #ifdef NON_ENCRYPTED_MODE sec_drv_read_flash(offset, pDest, blocksize); #else sec_drv_read_flash(offset, inbuffer, CRYPT_BLOCK_SIZE); cl_des((UBYTE *)inbuffer, (UBYTE *)GetDESKey(), (UBYTE *)outbuffer, (UBYTE)CL_DES_DECRYPTION); memcpy(pDest, outbuffer, blocksize); #endif offset += blocksize; pDest = (void *)((UINT32)pDest + blocksize); size -= blocksize; } while(size); } /** * Write a crypted block of the secure_area. * * @param offset Offset into the secure area from which to write the block. * @param pDest Pointer to the input buffer. * @param size Size of the block to write. Minimum 1. */ static void write_crypted_flash(UINT32 offset, const void *pSrc, UINT32 size) { UINT8 inbuffer[CRYPT_BLOCK_SIZE]; UINT8 outbuffer[CRYPT_BLOCK_SIZE]; UINT32 blocksize; assert(offset != 0L); assert(pSrc != 0L); assert(size > 0L); assert(offset >= 0L && (offset+size) <= SEC_FLASH_SIZE); sec_drv_flash_backup(); sec_drv_erase_flash(); do { blocksize = (size>CRYPT_BLOCK_SIZE)? CRYPT_BLOCK_SIZE : size; memset(inbuffer, 0, CRYPT_BLOCK_SIZE); memcpy(inbuffer, pSrc, blocksize); #ifdef NON_ENCRYPTED_MODE memcpy(outbuffer, inbuffer, CRYPT_BLOCK_SIZE); #else cl_des((UBYTE *)inbuffer, (UBYTE *)GetDESKey(), (UBYTE *)outbuffer, (UBYTE)CL_DES_ENCRYPTION); #endif /* write crypted datablock to flash */ sec_drv_write_flash(offset, outbuffer, CRYPT_BLOCK_SIZE); offset += blocksize; pSrc = (void *)((UINT32)pSrc + blocksize); size -= blocksize; } while(size); sec_drv_remove_backup(); } /******************************************* Offset calculations *******************************************/ static UINT32 offset_global_conf(void) { return 0; } static UINT32 offset_fc_key(void) { return ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_GLOBAL_CONF)); } static UINT32 offset_configuration(void) { return ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_GLOBAL_CONF)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_KEY)); } static UINT32 offset_category_key(int rec_num) { return ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_GLOBAL_CONF)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_KEY)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_CONFIGURATION)) + rec_num * (ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_KEY)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_CAT_HDR)) + ALIGN_CRYPT_BLOCK(SEC_DRV_CAT_MAX_SIZE)); } static UINT32 offset_category_header(int rec_num) { return ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_GLOBAL_CONF)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_KEY)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_CONFIGURATION)) + rec_num * (ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_KEY)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_CAT_HDR)) + ALIGN_CRYPT_BLOCK(SEC_DRV_CAT_MAX_SIZE)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_KEY)); } static UINT32 offset_category_body(int rec_num) { return ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_GLOBAL_CONF)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_KEY)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_CONFIGURATION)) + rec_num * (ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_KEY)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_CAT_HDR)) + ALIGN_CRYPT_BLOCK(SEC_DRV_CAT_MAX_SIZE)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_KEY)) + ALIGN_CRYPT_BLOCK(sizeof(T_SEC_DRV_CAT_HDR)); } /******************************************* Helper functions *******************************************/ /** * Check whether or not the secure area has been initialized. * * @return TRUE if the secure area has been initialized. */ static int check_firstboot_pattern_ok(void) { sec_prim_get_global_conf(0); if (gGlobalConf.firstboot_pattern != SEC_PATTERN_INITIALIZED) { TRACE("check_firstboot_pattern_ok - FAIL"); return FALSE; } return TRUE; } /** * Check whether or not the given number of categories is within bounds. * * @return TRUE if the given number of categories is within bounds. */ static int check_number_categories(int catNum) { BOOL result; if (!gMaxCategories) { T_SEC_DRV_CONFIGURATION conf; if (sec_prim_get_configuration(&conf)) { gMaxCategories = conf.NumCategories; HEXTRACE("check_number_categories - max: ", &gMaxCategories, sizeof(int)); } } return (catNum >= 0) && (catNum < gMaxCategories); } /******************************************* PRIMITIVES *******************************************/ /** * Read the global configuration for the secure flash area used to store * SIM lock data. * * @param pGlobalConf Pointer where to store the global configuration. * @return TRUE if the global configuration could be read. */ BOOL sec_prim_get_global_conf(T_SEC_DRV_GLOBAL_CONF *pGlobalConf) { if (!gGlobalConfRead) { sec_drv_read_flash(offset_global_conf(), &gGlobalConf, sizeof(T_SEC_DRV_GLOBAL_CONF)); HEXTRACE("sec_prim_get_global_conf: ", &gGlobalConf, sizeof(T_SEC_DRV_GLOBAL_CONF)); gGlobalConfRead = TRUE; } if (pGlobalConf != 0L) { memcpy(pGlobalConf, &gGlobalConf, sizeof(T_SEC_DRV_GLOBAL_CONF)); return TRUE; } return FALSE; } /** * Store the global configuration for the secure flash area used to store * SIM lock data. * * @param pGlobalConf Pointer to a global configuration. * @return TRUE if the global configuration could be written. */ BOOL sec_prim_set_global_conf(const T_SEC_DRV_GLOBAL_CONF *pGlobalConf) { /* Calc total size needed for this configuration */ if (pGlobalConf == 0L) return FALSE; HEXTRACE("sec_prim_set_global_conf: ", pGlobalConf, sizeof(T_SEC_DRV_GLOBAL_CONF)); sec_drv_flash_backup(); sec_drv_erase_flash(); sec_drv_write_flash(offset_global_conf(), pGlobalConf, sizeof(T_SEC_DRV_GLOBAL_CONF)); sec_drv_remove_backup(); gGlobalConfRead = FALSE; return TRUE; } /** * Read the configuration for the MEPD structure. * * @param pConf Pointer to buffer where the result will be placed * @Return 0 if flash area hasn't been configured. */ BOOL sec_prim_get_configuration(T_SEC_DRV_CONFIGURATION *pConf) { if (! check_firstboot_pattern_ok()) return FALSE; read_crypted_flash(offset_configuration(), pConf, sizeof(T_SEC_DRV_CONFIGURATION)); HEXTRACE("sec_prim_get_configuration: ", pConf, sizeof(T_SEC_DRV_CONFIGURATION)); return TRUE; } /** * Store the configuration for the MEPD structure. * * @param pConf Pointer to configuration to set * @Return TRUE if ok. */ BOOL sec_prim_set_configuration(const T_SEC_DRV_CONFIGURATION *pConf) { if (! check_firstboot_pattern_ok()) return FALSE; if (pConf == 0L) return FALSE; HEXTRACE("sec_prim_set_configuration: ", pConf, sizeof(T_SEC_DRV_CONFIGURATION)); write_crypted_flash(offset_configuration(), pConf, sizeof(T_SEC_DRV_CONFIGURATION)); gMaxCategories = 0; return TRUE; } /** * Read the key for either the failure counter (category -1) or a * lock-category (category 0..n). * * @param rec_num Category number to operate on * @param pKey Pointer to keybuffer * @Return TRUE if ok. */ BOOL sec_prim_get_key(int rec_num, T_SEC_DRV_KEY *pKey) { if (pKey!=0L) { if ((rec_num == -1) && (check_firstboot_pattern_ok())) { /* failure counter key */ read_crypted_flash(offset_fc_key(), pKey, sizeof(T_SEC_DRV_KEY)); HEXTRACE("sec_prim_get_key: ", pKey, sizeof(T_SEC_DRV_KEY)); return TRUE; } else if (check_number_categories(rec_num)) { /* category key */ read_crypted_flash(offset_category_key(rec_num), pKey, sizeof(T_SEC_DRV_KEY)); HEXTRACE("sec_prim_get_key: ", &rec_num, sizeof(int)); HEXTRACE("sec_prim_get_key: ", pKey, sizeof(T_SEC_DRV_KEY)); return TRUE; } } return FALSE; } /** * Store the key for either the failure counter (category -1) or a * lock-category (category 0..n). * * @param rec_num Category number to operate on * @param pKey Pointer to keybuffer * @Return TRUE if ok. */ BOOL sec_prim_set_key(int rec_num, const T_SEC_DRV_KEY *pKey) { if (pKey!=0L) { if ((rec_num == -1) && (check_firstboot_pattern_ok())) { /* failure counter key */ HEXTRACE("sec_prim_set_key - FC: ", pKey, sizeof(T_SEC_DRV_KEY)); write_crypted_flash(offset_fc_key(), pKey, sizeof(T_SEC_DRV_KEY)); return TRUE; } else if (check_number_categories(rec_num)) { /* category key */ HEXTRACE("sec_prim_set_key: ", &rec_num, sizeof(int)); HEXTRACE("sec_prim_set_key: ", pKey, sizeof(T_SEC_DRV_KEY)); write_crypted_flash(offset_category_key(rec_num), pKey, sizeof(T_SEC_DRV_KEY)); return TRUE; } } return FALSE; } /** * Read a lock-category header. * * @param rec_num Category number to operate on * @param pHdr Where to place the read category header? * @Return TRUE if ok. */ BOOL sec_prim_get_cat_header(int rec_num, T_SEC_DRV_CAT_HDR *pHdr) { if (!check_number_categories(rec_num)) return FALSE; if (pHdr == 0L) return FALSE; read_crypted_flash(offset_category_header(rec_num), pHdr, sizeof(T_SEC_DRV_CAT_HDR)); HEXTRACE("sec_prim_get_cat_header: ", &rec_num, sizeof(int)); HEXTRACE("sec_prim_get_cat_header: ", pHdr, sizeof(T_SEC_DRV_CAT_HDR)); return TRUE; } /** * Store a lock-category header. * * @param rec_num Category number to operate on * @param pHdr Pointer to the category header * @Return TRUE if ok. */ BOOL sec_prim_set_cat_header(int rec_num, const T_SEC_DRV_CAT_HDR *pHdr) { if (!check_number_categories(rec_num)) return FALSE; if (pHdr == 0L) return FALSE; HEXTRACE("sec_prim_set_cat_header: ", &rec_num, sizeof(int)); HEXTRACE("sec_prim_set_cat_header: ", pHdr, sizeof(T_SEC_DRV_CAT_HDR)); write_crypted_flash(offset_category_header(rec_num), pHdr, sizeof(T_SEC_DRV_CAT_HDR)); return TRUE; } /** * Read a lock-category body (client data). * * @param rec_num Category number to operate on * @param pBody Pointer to buffer where the result will be placed * @param size Size of the buffer * @Return TRUE if ok. */ BOOL sec_prim_get_cat_body(int rec_num, void *pBody, UINT16 size) { if (!check_number_categories(rec_num)) return FALSE; if (pBody == 0L) return FALSE; if (size==0 || size>SEC_DRV_CAT_MAX_SIZE) return FALSE; read_crypted_flash(offset_category_body(rec_num), pBody, size); HEXTRACE("sec_prim_get_cat_body: ", &rec_num, sizeof(int)); HEXTRACE("sec_prim_get_cat_body: ", pBody, size); return TRUE; } /** * Store a lock-category body (client data). * * @param rec_num Category number to operate on * @param pBody Pointer to data-buffer * @param size Size of the buffer * @Return TRUE if ok. */ BOOL sec_prim_set_cat_body(int rec_num, const void *pBody, UINT16 size) { T_SEC_DRV_CAT_HDR hdr; if (!check_number_categories(rec_num)) return FALSE; if (pBody == 0L) return FALSE; sec_prim_get_cat_header(rec_num, &hdr); if (hdr.DataLen != size) { hdr.DataLen = size; sec_prim_set_cat_header(rec_num, &hdr); } if (size) { HEXTRACE("sec_prim_set_cat_body: ", &rec_num, sizeof(int)); HEXTRACE("sec_prim_set_cat_body: ", pBody, size); write_crypted_flash(offset_category_body(rec_num), pBody, size); } return TRUE; }