123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903 |
- /*
- * Copyright 2015 Freescale Semiconductor, Inc.
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
- #include <common.h>
- #include <fsl_validate.h>
- #include <fsl_secboot_err.h>
- #include <fsl_sfp.h>
- #include <fsl_sec.h>
- #include <command.h>
- #include <malloc.h>
- #include <dm/uclass.h>
- #include <u-boot/rsa-mod-exp.h>
- #include <hash.h>
- #include <fsl_secboot_err.h>
- #ifdef CONFIG_LS102XA
- #include <asm/arch/immap_ls102xa.h>
- #endif
- #define SHA256_BITS 256
- #define SHA256_BYTES (256/8)
- #define SHA256_NIBBLES (256/4)
- #define NUM_HEX_CHARS (sizeof(ulong) * 2)
- #define CHECK_KEY_LEN(key_len) (((key_len) == 2 * KEY_SIZE_BYTES / 4) || \
- ((key_len) == 2 * KEY_SIZE_BYTES / 2) || \
- ((key_len) == 2 * KEY_SIZE_BYTES))
- /* This array contains DER value for SHA-256 */
- static const u8 hash_identifier[] = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
- 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
- 0x04, 0x20
- };
- static u8 hash_val[SHA256_BYTES];
- #ifdef CONFIG_ESBC_HDR_LS
- /* New Barker Code for LS ESBC Header */
- static const u8 barker_code[ESBC_BARKER_LEN] = { 0x12, 0x19, 0x20, 0x01 };
- #else
- static const u8 barker_code[ESBC_BARKER_LEN] = { 0x68, 0x39, 0x27, 0x81 };
- #endif
- void branch_to_self(void) __attribute__ ((noreturn));
- /*
- * This function will put core in infinite loop.
- * This will be called when the ESBC can not proceed further due
- * to some unknown errors.
- */
- void branch_to_self(void)
- {
- printf("Core is in infinite loop due to errors.\n");
- self:
- goto self;
- }
- #if defined(CONFIG_FSL_ISBC_KEY_EXT)
- static u32 check_ie(struct fsl_secboot_img_priv *img)
- {
- if (img->hdr.ie_flag)
- return 1;
- return 0;
- }
- /* This function returns the CSF Header Address of uboot
- * For MPC85xx based platforms, the LAW mapping for NOR
- * flash changes in uboot code. Hence the offset needs
- * to be calculated and added to the new NOR flash base
- * address
- */
- #if defined(CONFIG_MPC85xx)
- int get_csf_base_addr(u32 *csf_addr, u32 *flash_base_addr)
- {
- struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
- u32 csf_hdr_addr = in_be32(&gur->scratchrw[0]);
- u32 csf_flash_offset = csf_hdr_addr & ~(CONFIG_SYS_PBI_FLASH_BASE);
- u32 flash_addr, addr;
- int found = 0;
- int i = 0;
- for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
- flash_addr = flash_info[i].start[0];
- addr = flash_info[i].start[0] + csf_flash_offset;
- if (memcmp((u8 *)addr, barker_code, ESBC_BARKER_LEN) == 0) {
- debug("Barker found on addr %x\n", addr);
- found = 1;
- break;
- }
- }
- if (!found)
- return -1;
- *csf_addr = addr;
- *flash_base_addr = flash_addr;
- return 0;
- }
- #else
- /* For platforms like LS1020, correct flash address is present in
- * the header. So the function reqturns flash base address as 0
- */
- int get_csf_base_addr(u32 *csf_addr, u32 *flash_base_addr)
- {
- struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
- u32 csf_hdr_addr = in_be32(&gur->scratchrw[0]);
- if (memcmp((u8 *)(uintptr_t)csf_hdr_addr,
- barker_code, ESBC_BARKER_LEN))
- return -1;
- *csf_addr = csf_hdr_addr;
- *flash_base_addr = 0;
- return 0;
- }
- #endif
- static int get_ie_info_addr(u32 *ie_addr)
- {
- struct fsl_secboot_img_hdr *hdr;
- struct fsl_secboot_sg_table *sg_tbl;
- u32 flash_base_addr, csf_addr;
- if (get_csf_base_addr(&csf_addr, &flash_base_addr))
- return -1;
- hdr = (struct fsl_secboot_img_hdr *)(uintptr_t)csf_addr;
- /* For SoC's with Trust Architecture v1 with corenet bus
- * the sg table field in CSF header has absolute address
- * for sg table in memory. In other Trust Architecture,
- * this field specifies the offset of sg table from the
- * base address of CSF Header
- */
- #if defined(CONFIG_FSL_TRUST_ARCH_v1) && defined(CONFIG_FSL_CORENET)
- sg_tbl = (struct fsl_secboot_sg_table *)
- (((u32)hdr->psgtable & ~(CONFIG_SYS_PBI_FLASH_BASE)) +
- flash_base_addr);
- #else
- sg_tbl = (struct fsl_secboot_sg_table *)(uintptr_t)(csf_addr +
- (u32)hdr->psgtable);
- #endif
- /* IE Key Table is the first entry in the SG Table */
- #if defined(CONFIG_MPC85xx)
- *ie_addr = (sg_tbl->src_addr & ~(CONFIG_SYS_PBI_FLASH_BASE)) +
- flash_base_addr;
- #else
- *ie_addr = sg_tbl->src_addr;
- #endif
- debug("IE Table address is %x\n", *ie_addr);
- return 0;
- }
- #endif
- #ifdef CONFIG_KEY_REVOCATION
- /* This function checks srk_table_flag in header and set/reset srk_flag.*/
- static u32 check_srk(struct fsl_secboot_img_priv *img)
- {
- #ifdef CONFIG_ESBC_HDR_LS
- /* In LS, No SRK Flag as SRK is always present*/
- return 1;
- #else
- if (img->hdr.len_kr.srk_table_flag & SRK_FLAG)
- return 1;
- return 0;
- #endif
- }
- /* This function returns ospr's key_revoc values.*/
- static u32 get_key_revoc(void)
- {
- struct ccsr_sfp_regs *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
- return (sfp_in32(&sfp_regs->ospr) & OSPR_KEY_REVOC_MASK) >>
- OSPR_KEY_REVOC_SHIFT;
- }
- /* This function checks if selected key is revoked or not.*/
- static u32 is_key_revoked(u32 keynum, u32 rev_flag)
- {
- if (keynum == UNREVOCABLE_KEY)
- return 0;
- if ((u32)(1 << (ALIGN_REVOC_KEY - keynum)) & rev_flag)
- return 1;
- return 0;
- }
- /* It read validates srk_table key lengths.*/
- static u32 read_validate_srk_tbl(struct fsl_secboot_img_priv *img)
- {
- int i = 0;
- u32 ret, key_num, key_revoc_flag, size;
- struct fsl_secboot_img_hdr *hdr = &img->hdr;
- void *esbc = (u8 *)(uintptr_t)img->ehdrloc;
- if ((hdr->len_kr.num_srk == 0) ||
- (hdr->len_kr.num_srk > MAX_KEY_ENTRIES))
- return ERROR_ESBC_CLIENT_HEADER_INVALID_SRK_NUM_ENTRY;
- key_num = hdr->len_kr.srk_sel;
- if (key_num == 0 || key_num > hdr->len_kr.num_srk)
- return ERROR_ESBC_CLIENT_HEADER_INVALID_KEY_NUM;
- /* Get revoc key from sfp */
- key_revoc_flag = get_key_revoc();
- ret = is_key_revoked(key_num, key_revoc_flag);
- if (ret)
- return ERROR_ESBC_CLIENT_HEADER_KEY_REVOKED;
- size = hdr->len_kr.num_srk * sizeof(struct srk_table);
- memcpy(&img->srk_tbl, esbc + hdr->srk_tbl_off, size);
- for (i = 0; i < hdr->len_kr.num_srk; i++) {
- if (!CHECK_KEY_LEN(img->srk_tbl[i].key_len))
- return ERROR_ESBC_CLIENT_HEADER_INV_SRK_ENTRY_KEYLEN;
- }
- img->key_len = img->srk_tbl[key_num - 1].key_len;
- memcpy(&img->img_key, &(img->srk_tbl[key_num - 1].pkey),
- img->key_len);
- return 0;
- }
- #endif
- #ifndef CONFIG_ESBC_HDR_LS
- static u32 read_validate_single_key(struct fsl_secboot_img_priv *img)
- {
- struct fsl_secboot_img_hdr *hdr = &img->hdr;
- void *esbc = (u8 *)(uintptr_t)img->ehdrloc;
- /* check key length */
- if (!CHECK_KEY_LEN(hdr->key_len))
- return ERROR_ESBC_CLIENT_HEADER_KEY_LEN;
- memcpy(&img->img_key, esbc + hdr->pkey, hdr->key_len);
- img->key_len = hdr->key_len;
- return 0;
- }
- #endif /* CONFIG_ESBC_HDR_LS */
- #if defined(CONFIG_FSL_ISBC_KEY_EXT)
- static u32 read_validate_ie_tbl(struct fsl_secboot_img_priv *img)
- {
- struct fsl_secboot_img_hdr *hdr = &img->hdr;
- u32 ie_key_len, ie_revoc_flag, ie_num;
- struct ie_key_info *ie_info;
- if (get_ie_info_addr(&img->ie_addr))
- return ERROR_IE_TABLE_NOT_FOUND;
- ie_info = (struct ie_key_info *)(uintptr_t)img->ie_addr;
- if (ie_info->num_keys == 0 || ie_info->num_keys > 32)
- return ERROR_ESBC_CLIENT_HEADER_INVALID_IE_NUM_ENTRY;
- ie_num = hdr->ie_key_sel;
- if (ie_num == 0 || ie_num > ie_info->num_keys)
- return ERROR_ESBC_CLIENT_HEADER_INVALID_IE_KEY_NUM;
- ie_revoc_flag = ie_info->key_revok;
- if ((u32)(1 << (ie_num - 1)) & ie_revoc_flag)
- return ERROR_ESBC_CLIENT_HEADER_IE_KEY_REVOKED;
- ie_key_len = ie_info->ie_key_tbl[ie_num - 1].key_len;
- if (!CHECK_KEY_LEN(ie_key_len))
- return ERROR_ESBC_CLIENT_HEADER_INV_IE_ENTRY_KEYLEN;
- memcpy(&img->img_key, &(ie_info->ie_key_tbl[ie_num - 1].pkey),
- ie_key_len);
- img->key_len = ie_key_len;
- return 0;
- }
- #endif
- /* This function return length of public key.*/
- static inline u32 get_key_len(struct fsl_secboot_img_priv *img)
- {
- return img->key_len;
- }
- /*
- * Handles the ESBC uboot client header verification failure.
- * This function handles all the errors which might occur in the
- * parsing and checking of ESBC uboot client header. It will also
- * set the error bits in the SEC_MON.
- */
- static void fsl_secboot_header_verification_failure(void)
- {
- struct ccsr_sfp_regs *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
- /* 29th bit of OSPR is ITS */
- u32 its = sfp_in32(&sfp_regs->ospr) >> 2;
- if (its == 1)
- set_sec_mon_state(HPSR_SSM_ST_SOFT_FAIL);
- else
- set_sec_mon_state(HPSR_SSM_ST_NON_SECURE);
- printf("Generating reset request\n");
- do_reset(NULL, 0, 0, NULL);
- /* If reset doesn't coocur, halt execution */
- do_esbc_halt(NULL, 0, 0, NULL);
- }
- /*
- * Handles the ESBC uboot client image verification failure.
- * This function handles all the errors which might occur in the
- * public key hash comparison and signature verification of
- * ESBC uboot client image. It will also
- * set the error bits in the SEC_MON.
- */
- static void fsl_secboot_image_verification_failure(void)
- {
- struct ccsr_sfp_regs *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
- u32 its = (sfp_in32(&sfp_regs->ospr) & ITS_MASK) >> ITS_BIT;
- if (its == 1) {
- set_sec_mon_state(HPSR_SSM_ST_SOFT_FAIL);
- printf("Generating reset request\n");
- do_reset(NULL, 0, 0, NULL);
- /* If reset doesn't coocur, halt execution */
- do_esbc_halt(NULL, 0, 0, NULL);
- } else {
- set_sec_mon_state(HPSR_SSM_ST_NON_SECURE);
- }
- }
- static void fsl_secboot_bootscript_parse_failure(void)
- {
- fsl_secboot_header_verification_failure();
- }
- /*
- * Handles the errors in esbc boot.
- * This function handles all the errors which might occur in the
- * esbc boot phase. It will call the appropriate api to log the
- * errors and set the error bits in the SEC_MON.
- */
- void fsl_secboot_handle_error(int error)
- {
- const struct fsl_secboot_errcode *e;
- for (e = fsl_secboot_errcodes; e->errcode != ERROR_ESBC_CLIENT_MAX;
- e++) {
- if (e->errcode == error)
- printf("ERROR :: %x :: %s\n", error, e->name);
- }
- /* If Boot Mode is secure, transition the SNVS state and issue
- * reset based on type of failure and ITS setting.
- * If Boot mode is non-secure, return from this function.
- */
- if (fsl_check_boot_mode_secure() == 0)
- return;
- switch (error) {
- case ERROR_ESBC_CLIENT_HEADER_BARKER:
- case ERROR_ESBC_CLIENT_HEADER_IMG_SIZE:
- case ERROR_ESBC_CLIENT_HEADER_KEY_LEN:
- case ERROR_ESBC_CLIENT_HEADER_SIG_LEN:
- case ERROR_ESBC_CLIENT_HEADER_KEY_LEN_NOT_TWICE_SIG_LEN:
- case ERROR_ESBC_CLIENT_HEADER_KEY_MOD_1:
- case ERROR_ESBC_CLIENT_HEADER_KEY_MOD_2:
- case ERROR_ESBC_CLIENT_HEADER_SIG_KEY_MOD:
- case ERROR_ESBC_CLIENT_HEADER_SG_ESBC_EP:
- case ERROR_ESBC_CLIENT_HEADER_SG_ENTIRES_BAD:
- case ERROR_KEY_TABLE_NOT_FOUND:
- #ifdef CONFIG_KEY_REVOCATION
- case ERROR_ESBC_CLIENT_HEADER_KEY_REVOKED:
- case ERROR_ESBC_CLIENT_HEADER_INVALID_SRK_NUM_ENTRY:
- case ERROR_ESBC_CLIENT_HEADER_INVALID_KEY_NUM:
- case ERROR_ESBC_CLIENT_HEADER_INV_SRK_ENTRY_KEYLEN:
- #endif
- #if defined(CONFIG_FSL_ISBC_KEY_EXT)
- /*@fallthrough@*/
- case ERROR_ESBC_CLIENT_HEADER_IE_KEY_REVOKED:
- case ERROR_ESBC_CLIENT_HEADER_INVALID_IE_NUM_ENTRY:
- case ERROR_ESBC_CLIENT_HEADER_INVALID_IE_KEY_NUM:
- case ERROR_ESBC_CLIENT_HEADER_INV_IE_ENTRY_KEYLEN:
- case ERROR_IE_TABLE_NOT_FOUND:
- #endif
- fsl_secboot_header_verification_failure();
- break;
- case ERROR_ESBC_SEC_RESET:
- case ERROR_ESBC_SEC_DEQ:
- case ERROR_ESBC_SEC_ENQ:
- case ERROR_ESBC_SEC_DEQ_TO:
- case ERROR_ESBC_SEC_JOBQ_STATUS:
- case ERROR_ESBC_CLIENT_HASH_COMPARE_KEY:
- case ERROR_ESBC_CLIENT_HASH_COMPARE_EM:
- fsl_secboot_image_verification_failure();
- break;
- case ERROR_ESBC_MISSING_BOOTM:
- fsl_secboot_bootscript_parse_failure();
- break;
- case ERROR_ESBC_WRONG_CMD:
- default:
- branch_to_self();
- break;
- }
- }
- static void fsl_secblk_handle_error(int error)
- {
- switch (error) {
- case ERROR_ESBC_SEC_ENQ:
- fsl_secboot_handle_error(ERROR_ESBC_SEC_ENQ);
- break;
- case ERROR_ESBC_SEC_DEQ:
- fsl_secboot_handle_error(ERROR_ESBC_SEC_DEQ);
- break;
- case ERROR_ESBC_SEC_DEQ_TO:
- fsl_secboot_handle_error(ERROR_ESBC_SEC_DEQ_TO);
- break;
- default:
- printf("Job Queue Output status %x\n", error);
- fsl_secboot_handle_error(ERROR_ESBC_SEC_JOBQ_STATUS);
- break;
- }
- }
- /*
- * Calculate hash of key obtained via offset present in ESBC uboot
- * client hdr. This function calculates the hash of key which is obtained
- * through offset present in ESBC uboot client header.
- */
- static int calc_img_key_hash(struct fsl_secboot_img_priv *img)
- {
- struct hash_algo *algo;
- void *ctx;
- int i, srk = 0;
- int ret = 0;
- const char *algo_name = "sha256";
- /* Calculate hash of the esbc key */
- ret = hash_progressive_lookup_algo(algo_name, &algo);
- if (ret)
- return ret;
- ret = algo->hash_init(algo, &ctx);
- if (ret)
- return ret;
- /* Update hash for ESBC key */
- #ifdef CONFIG_KEY_REVOCATION
- if (check_srk(img)) {
- ret = algo->hash_update(algo, ctx,
- (u8 *)(uintptr_t)(img->ehdrloc + img->hdr.srk_tbl_off),
- img->hdr.len_kr.num_srk * sizeof(struct srk_table), 1);
- srk = 1;
- }
- #endif
- if (!srk)
- ret = algo->hash_update(algo, ctx,
- img->img_key, img->key_len, 1);
- if (ret)
- return ret;
- /* Copy hash at destination buffer */
- ret = algo->hash_finish(algo, ctx, hash_val, algo->digest_size);
- if (ret)
- return ret;
- for (i = 0; i < SHA256_BYTES; i++)
- img->img_key_hash[i] = hash_val[i];
- return 0;
- }
- /*
- * Calculate hash of ESBC hdr and ESBC. This function calculates the
- * single hash of ESBC header and ESBC image. If SG flag is on, all
- * SG entries are also hashed alongwith the complete SG table.
- */
- static int calc_esbchdr_esbc_hash(struct fsl_secboot_img_priv *img)
- {
- struct hash_algo *algo;
- void *ctx;
- int ret = 0;
- int key_hash = 0;
- const char *algo_name = "sha256";
- /* Calculate the hash of the ESBC */
- ret = hash_progressive_lookup_algo(algo_name, &algo);
- if (ret)
- return ret;
- ret = algo->hash_init(algo, &ctx);
- /* Copy hash at destination buffer */
- if (ret)
- return ret;
- /* Update hash for CSF Header */
- ret = algo->hash_update(algo, ctx,
- (u8 *)&img->hdr, sizeof(struct fsl_secboot_img_hdr), 0);
- if (ret)
- return ret;
- /* Update the hash with that of srk table if srk flag is 1
- * If IE Table is selected, key is not added in the hash
- * If neither srk table nor IE key table available, add key
- * from header in the hash calculation
- */
- #ifdef CONFIG_KEY_REVOCATION
- if (check_srk(img)) {
- ret = algo->hash_update(algo, ctx,
- (u8 *)(uintptr_t)(img->ehdrloc + img->hdr.srk_tbl_off),
- img->hdr.len_kr.num_srk * sizeof(struct srk_table), 0);
- key_hash = 1;
- }
- #endif
- #if defined(CONFIG_FSL_ISBC_KEY_EXT)
- if (!key_hash && check_ie(img))
- key_hash = 1;
- #endif
- #ifndef CONFIG_ESBC_HDR_LS
- /* No single key support in LS ESBC header */
- if (!key_hash) {
- ret = algo->hash_update(algo, ctx,
- img->img_key, img->hdr.key_len, 0);
- key_hash = 1;
- }
- #endif
- if (ret)
- return ret;
- if (!key_hash)
- return ERROR_KEY_TABLE_NOT_FOUND;
- /* Update hash for actual Image */
- ret = algo->hash_update(algo, ctx,
- (u8 *)(*(img->img_addr_ptr)), img->img_size, 1);
- if (ret)
- return ret;
- /* Copy hash at destination buffer */
- ret = algo->hash_finish(algo, ctx, hash_val, algo->digest_size);
- if (ret)
- return ret;
- return 0;
- }
- /*
- * Construct encoded hash EM' wrt PKCSv1.5. This function calculates the
- * pointers for padding, DER value and hash. And finally, constructs EM'
- * which includes hash of complete CSF header and ESBC image. If SG flag
- * is on, hash of SG table and entries is also included.
- */
- static void construct_img_encoded_hash_second(struct fsl_secboot_img_priv *img)
- {
- /*
- * RSA PKCSv1.5 encoding format for encoded message is below
- * EM = 0x0 || 0x1 || PS || 0x0 || DER || Hash
- * PS is Padding String
- * DER is DER value for SHA-256
- * Hash is SHA-256 hash
- * *********************************************************
- * representative points to first byte of EM initially and is
- * filled with 0x0
- * representative is incremented by 1 and second byte is filled
- * with 0x1
- * padding points to third byte of EM
- * digest points to full length of EM - 32 bytes
- * hash_id (DER value) points to 19 bytes before pDigest
- * separator is one byte which separates padding and DER
- */
- size_t len;
- u8 *representative;
- u8 *padding, *digest;
- u8 *hash_id, *separator;
- int i;
- len = (get_key_len(img) / 2) - 1;
- representative = img->img_encoded_hash_second;
- representative[0] = 0;
- representative[1] = 1; /* block type 1 */
- padding = &representative[2];
- digest = &representative[1] + len - 32;
- hash_id = digest - sizeof(hash_identifier);
- separator = hash_id - 1;
- /* fill padding area pointed by padding with 0xff */
- memset(padding, 0xff, separator - padding);
- /* fill byte pointed by separator */
- *separator = 0;
- /* fill SHA-256 DER value pointed by HashId */
- memcpy(hash_id, hash_identifier, sizeof(hash_identifier));
- /* fill hash pointed by Digest */
- for (i = 0; i < SHA256_BYTES; i++)
- digest[i] = hash_val[i];
- }
- /*
- * Reads and validates the ESBC client header.
- * This function reads key and signature from the ESBC client header.
- * If Scatter/Gather flag is on, lengths and offsets of images
- * present as SG entries are also read. This function also checks
- * whether the header is valid or not.
- */
- static int read_validate_esbc_client_header(struct fsl_secboot_img_priv *img)
- {
- struct fsl_secboot_img_hdr *hdr = &img->hdr;
- void *esbc = (u8 *)(uintptr_t)img->ehdrloc;
- u8 *k, *s;
- u32 ret = 0;
- int key_found = 0;
- /* check barker code */
- if (memcmp(hdr->barker, barker_code, ESBC_BARKER_LEN))
- return ERROR_ESBC_CLIENT_HEADER_BARKER;
- /* If Image Address is not passed as argument to function,
- * then Address and Size must be read from the Header.
- */
- if (*(img->img_addr_ptr) == 0) {
- #ifdef CONFIG_ESBC_ADDR_64BIT
- *(img->img_addr_ptr) = hdr->pimg64;
- #else
- *(img->img_addr_ptr) = hdr->pimg;
- #endif
- }
- if (!hdr->img_size)
- return ERROR_ESBC_CLIENT_HEADER_IMG_SIZE;
- img->img_size = hdr->img_size;
- /* Key checking*/
- #ifdef CONFIG_KEY_REVOCATION
- if (check_srk(img)) {
- ret = read_validate_srk_tbl(img);
- if (ret != 0)
- return ret;
- key_found = 1;
- }
- #endif
- #if defined(CONFIG_FSL_ISBC_KEY_EXT)
- if (!key_found && check_ie(img)) {
- ret = read_validate_ie_tbl(img);
- if (ret != 0)
- return ret;
- key_found = 1;
- }
- #endif
- #ifndef CONFIG_ESBC_HDR_LS
- /* Single Key Feature not available in LS ESBC Header */
- if (key_found == 0) {
- ret = read_validate_single_key(img);
- if (ret != 0)
- return ret;
- key_found = 1;
- }
- #endif
- if (!key_found)
- return ERROR_KEY_TABLE_NOT_FOUND;
- /* check signaure */
- if (get_key_len(img) == 2 * hdr->sign_len) {
- /* check signature length */
- if (!((hdr->sign_len == KEY_SIZE_BYTES / 4) ||
- (hdr->sign_len == KEY_SIZE_BYTES / 2) ||
- (hdr->sign_len == KEY_SIZE_BYTES)))
- return ERROR_ESBC_CLIENT_HEADER_SIG_LEN;
- } else {
- return ERROR_ESBC_CLIENT_HEADER_KEY_LEN_NOT_TWICE_SIG_LEN;
- }
- memcpy(&img->img_sign, esbc + hdr->psign, hdr->sign_len);
- /* No SG support in LS-CH3 */
- #ifndef CONFIG_ESBC_HDR_LS
- /* No SG support */
- if (hdr->sg_flag)
- return ERROR_ESBC_CLIENT_HEADER_SG;
- #endif
- /* modulus most significant bit should be set */
- k = (u8 *)&img->img_key;
- if ((k[0] & 0x80) == 0)
- return ERROR_ESBC_CLIENT_HEADER_KEY_MOD_1;
- /* modulus value should be odd */
- if ((k[get_key_len(img) / 2 - 1] & 0x1) == 0)
- return ERROR_ESBC_CLIENT_HEADER_KEY_MOD_2;
- /* Check signature value < modulus value */
- s = (u8 *)&img->img_sign;
- if (!(memcmp(s, k, hdr->sign_len) < 0))
- return ERROR_ESBC_CLIENT_HEADER_SIG_KEY_MOD;
- return ESBC_VALID_HDR;
- }
- static inline int str2longbe(const char *p, ulong *num)
- {
- char *endptr;
- ulong tmp;
- if (!p) {
- return 0;
- } else {
- tmp = simple_strtoul(p, &endptr, 16);
- if (sizeof(ulong) == 4)
- *num = cpu_to_be32(tmp);
- else
- *num = cpu_to_be64(tmp);
- }
- return *p != '\0' && *endptr == '\0';
- }
- /* Function to calculate the ESBC Image Hash
- * and hash from Digital signature.
- * The Two hash's are compared to yield the
- * result of signature validation.
- */
- static int calculate_cmp_img_sig(struct fsl_secboot_img_priv *img)
- {
- int ret;
- uint32_t key_len;
- struct key_prop prop;
- #if !defined(USE_HOSTCC)
- struct udevice *mod_exp_dev;
- #endif
- ret = calc_esbchdr_esbc_hash(img);
- if (ret)
- return ret;
- /* Construct encoded hash EM' wrt PKCSv1.5 */
- construct_img_encoded_hash_second(img);
- /* Fill prop structure for public key */
- memset(&prop, 0, sizeof(struct key_prop));
- key_len = get_key_len(img) / 2;
- prop.modulus = img->img_key;
- prop.public_exponent = img->img_key + key_len;
- prop.num_bits = key_len * 8;
- prop.exp_len = key_len;
- ret = uclass_get_device(UCLASS_MOD_EXP, 0, &mod_exp_dev);
- if (ret) {
- printf("RSA: Can't find Modular Exp implementation\n");
- return -EINVAL;
- }
- ret = rsa_mod_exp(mod_exp_dev, img->img_sign, img->hdr.sign_len,
- &prop, img->img_encoded_hash);
- if (ret)
- return ret;
- /*
- * compare the encoded messages EM' and EM wrt RSA PKCSv1.5
- * memcmp returns zero on success
- * memcmp returns non-zero on failure
- */
- ret = memcmp(&img->img_encoded_hash_second, &img->img_encoded_hash,
- img->hdr.sign_len);
- if (ret)
- return ERROR_ESBC_CLIENT_HASH_COMPARE_EM;
- return 0;
- }
- /* haddr - Address of the header of image to be validated.
- * arg_hash_str - Option hash string. If provided, this
- * overrides the key hash in the SFP fuses.
- * img_addr_ptr - Optional pointer to address of image to be validated.
- * If non zero addr, this overrides the addr of image in header,
- * otherwise updated to image addr in header.
- * Acts as both input and output of function.
- * This pointer shouldn't be NULL.
- */
- int fsl_secboot_validate(uintptr_t haddr, char *arg_hash_str,
- uintptr_t *img_addr_ptr)
- {
- struct ccsr_sfp_regs *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
- ulong hash[SHA256_BYTES/sizeof(ulong)];
- char hash_str[NUM_HEX_CHARS + 1];
- struct fsl_secboot_img_priv *img;
- struct fsl_secboot_img_hdr *hdr;
- void *esbc;
- int ret, i, hash_cmd = 0;
- u32 srk_hash[8];
- if (arg_hash_str != NULL) {
- const char *cp = arg_hash_str;
- int i = 0;
- if (*cp == '0' && *(cp + 1) == 'x')
- cp += 2;
- /* The input string expected is in hex, where
- * each 4 bits would be represented by a hex
- * sha256 hash is 256 bits long, which would mean
- * num of characters = 256 / 4
- */
- if (strlen(cp) != SHA256_NIBBLES) {
- printf("%s is not a 256 bits hex string as expected\n",
- arg_hash_str);
- return -1;
- }
- for (i = 0; i < sizeof(hash)/sizeof(ulong); i++) {
- strncpy(hash_str, cp + (i * NUM_HEX_CHARS),
- NUM_HEX_CHARS);
- hash_str[NUM_HEX_CHARS] = '\0';
- if (!str2longbe(hash_str, &hash[i])) {
- printf("%s is not a 256 bits hex string ",
- arg_hash_str);
- return -1;
- }
- }
- hash_cmd = 1;
- }
- img = malloc(sizeof(struct fsl_secboot_img_priv));
- if (!img)
- return -1;
- memset(img, 0, sizeof(struct fsl_secboot_img_priv));
- /* Update the information in Private Struct */
- hdr = &img->hdr;
- img->ehdrloc = haddr;
- img->img_addr_ptr = img_addr_ptr;
- esbc = (u8 *)img->ehdrloc;
- memcpy(hdr, esbc, sizeof(struct fsl_secboot_img_hdr));
- /* read and validate esbc header */
- ret = read_validate_esbc_client_header(img);
- if (ret != ESBC_VALID_HDR) {
- fsl_secboot_handle_error(ret);
- goto exit;
- }
- /* SRKH present in SFP */
- for (i = 0; i < NUM_SRKH_REGS; i++)
- srk_hash[i] = srk_in32(&sfp_regs->srk_hash[i]);
- /*
- * Calculate hash of key obtained via offset present in
- * ESBC uboot client hdr
- */
- ret = calc_img_key_hash(img);
- if (ret) {
- fsl_secblk_handle_error(ret);
- goto exit;
- }
- /* Compare hash obtained above with SRK hash present in SFP */
- if (hash_cmd)
- ret = memcmp(&hash, &img->img_key_hash, SHA256_BYTES);
- else
- ret = memcmp(srk_hash, img->img_key_hash, SHA256_BYTES);
- #if defined(CONFIG_FSL_ISBC_KEY_EXT)
- if (!hash_cmd && check_ie(img))
- ret = 0;
- #endif
- if (ret != 0) {
- fsl_secboot_handle_error(ERROR_ESBC_CLIENT_HASH_COMPARE_KEY);
- goto exit;
- }
- ret = calculate_cmp_img_sig(img);
- if (ret) {
- fsl_secboot_handle_error(ret);
- goto exit;
- }
- exit:
- return ret;
- }
|