[Feature]add MT2731_MP2_MR2_SVN388 baseline version
Change-Id: Ief04314834b31e27effab435d3ca8ba33b499059
diff --git a/src/bsp/lk/lib/fit/fit.c b/src/bsp/lk/lib/fit/fit.c
new file mode 100644
index 0000000..b015c56
--- /dev/null
+++ b/src/bsp/lk/lib/fit/fit.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <arch/ops.h>
+#include <errno.h>
+#include <lib/bio.h>
+#include <libfdt.h>
+#include <lib/decompress.h>
+#include <lib/mempool.h>
+#include <kernel/thread.h>
+#include <kernel/vm.h>
+#include <trace.h>
+
+#include "fit.h"
+#include "image.h"
+
+#define LOCAL_TRACE 0
+
+#define uswap_32(x) \
+ ((((x) & 0xff000000) >> 24) | \
+ (((x) & 0x00ff0000) >> 8) | \
+ (((x) & 0x0000ff00) << 8) | \
+ (((x) & 0x000000ff) << 24))
+
+int fit_image_get_node(const void *fit, const char *image_uname)
+{
+ int noffset, images_noffset;
+
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ dprintf(CRITICAL,"Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror(images_noffset));
+ return images_noffset;
+ }
+
+ noffset = fdt_subnode_offset(fit, images_noffset, image_uname);
+ if (noffset < 0) {
+ dprintf(CRITICAL,"Can't get node offset for image name: '%s' (%s)\n",
+ image_uname, fdt_strerror(noffset));
+ }
+
+ return noffset;
+}
+
+int fit_image_get_data(const void *fit, int noffset,
+ const void **data, uint32_t *size)
+{
+ int len;
+ *data = fdt_getprop(fit, noffset, FDT_DATA_NODE, &len);
+ if (*data == NULL)
+ return -1;
+
+ *size = len;
+
+ return 0;
+}
+
+int fit_conf_get_prop_node(const void *fit, int noffset,
+ const char *prop_name)
+{
+ char *uname;
+ int len;
+
+ /* get kernel image unit name from configuration kernel property */
+ uname = (char *)fdt_getprop(fit, noffset, prop_name, &len);
+ if (uname == NULL)
+ return len;
+
+ return fit_image_get_node(fit, uname);
+}
+
+/**
+ * fit_get_img_subnode_offset() - get a subnode offset for a given image name
+ *
+ * This finds subnode offset using given image name within node "/images"
+ *
+ * @fit: fit image start address
+ * @image_name: image name. "kernel", "fdt" or "ramdisk"...
+ *
+ * returns:
+ * great than or equal 0, on success
+ * otherwise, on failure
+ *
+ */
+static int fit_get_img_subnode_offset(void *fit, const char *image_name)
+{
+ int noffset;
+
+ /* get image node offset */
+ noffset = fdt_path_offset(fit, "/images");
+ if (noffset < 0) {
+ dprintf(CRITICAL, "Can't find image node(%s)\n", fdt_strerror(noffset));
+ return noffset;
+ }
+
+ /* get subnode offset */
+ noffset = fdt_subnode_offset(fit, noffset, image_name);
+ if (noffset < 0)
+ dprintf(CRITICAL, "Can't get node offset for image name: '%s' (%s)\n",
+ image_name, fdt_strerror(noffset));
+
+ return noffset;
+}
+
+/**
+ * fit_get_def_cfg_offset() - get a subnode offset from node "/configurations"
+ *
+ * This finds configuration subnode offset in node "configruations".
+ * If "conf" is not given, it will find property "default" for the case.
+ *
+ * @fit: fit image start address
+ * @conf: configuration name
+ *
+ * returns:
+ * great than or equal 0, on success
+ * otherwise, on failure
+ *
+ */
+static int fit_get_def_cfg_offset(void *fit, const char *conf)
+{
+ int noffset, cfg_noffset, len;
+
+ noffset = fdt_path_offset(fit, "/configurations");
+ if (noffset < 0) {
+ dprintf(CRITICAL, "can't find configuration node\n");
+ return noffset;
+ }
+
+ if (conf == NULL) {
+ conf = (char *)fdt_getprop(fit, noffset,
+ "default", &len);
+ if (conf == NULL) {
+ dprintf(CRITICAL, "Can't get default conf name\n");
+ return len;
+ }
+ dprintf(SPEW, "got default conf: %s\n", conf);
+ }
+
+ cfg_noffset = fdt_subnode_offset(fit, noffset, conf);
+ if (cfg_noffset < 0)
+ dprintf(CRITICAL, "Can't get conf subnode\n");
+ else
+ dprintf(SPEW, "got conf: %s subnode\n", conf);
+
+ return cfg_noffset;
+}
+
+int fit_get_image(const char *label, void **load_buf)
+{
+ bdev_t *bdev;
+ struct fdt_header fdt;
+ size_t totalsize;
+ int fdt_len, ret = 0;
+ void *fit_buf = NULL;
+
+ fdt_len = sizeof(struct fdt_header);
+ bdev = bio_open_by_label(label) ? : bio_open(label);
+ if (!bdev) {
+ dprintf(CRITICAL, "Partition [%s] is not exist.\n", label);
+ return -ENODEV;
+ }
+
+ if (bio_read(bdev, &fdt, 0, fdt_len) < fdt_len) {
+ ret = -EIO;
+ goto closebdev;
+ }
+
+ ret = fdt_check_header(&fdt);
+ if (ret) {
+ dprintf(CRITICAL, "[%s] check header failed\n", label);
+ goto closebdev;
+ }
+
+ totalsize = fdt_totalsize(&fdt);
+ fit_buf = mempool_alloc(totalsize, MEMPOOL_ANY);
+ if (!fit_buf) {
+ ret = -ENOMEM;
+ goto closebdev;
+ }
+
+ if (bio_read(bdev, fit_buf, 0, totalsize) < totalsize) {
+ ret = -EIO;
+ goto closebdev;
+ }
+ *load_buf = fit_buf;
+
+closebdev:
+ bio_close(bdev);
+ if ((ret != 0) && (fit_buf != NULL))
+ mempool_free(fit_buf);
+
+ return ret;
+}
+
+int fit_processing_data(void *fit, const char *image_name, int noffset,
+ addr_t *load, size_t *load_size, paddr_t *entry)
+{
+ int len, ret, ac;
+ size_t size;
+ const char *type;
+ const void *data, *compression;
+ const uint32_t *load_prop, *entry_prop;
+ addr_t load_addr;
+ paddr_t entry_addr;
+
+ data = fdt_getprop(fit, noffset, "data", &len);
+ if (!data) {
+ dprintf(CRITICAL, "%s can't get prop data\n", image_name);
+ return len;
+ }
+ size = len;
+
+ compression = fdt_getprop(fit, noffset, "compression", &len);
+ if (!compression) {
+ dprintf(CRITICAL, "%s compression is not specified\n", image_name);
+ return -EINVAL;
+ }
+
+ type = fdt_getprop(fit, noffset, "type", &len);
+ if (!type) {
+ dprintf(CRITICAL, "%s image type is not specified\n", image_name);
+ return -EINVAL;
+ }
+
+ /* read address-cells from root */
+ ac = fdt_address_cells(fit, 0);
+ if (ac <= 0 || (ac > sizeof(ulong) / sizeof(uint))) {
+ LTRACEF("%s #address-cells with a bad format or value\n", image_name);
+ return -EINVAL;
+ }
+
+ load_prop = fdt_getprop(fit, noffset, "load", &len);
+ if (!load_prop &&
+ (!strcmp(type, "kernel") || (!strcmp(type, "loadable")))) {
+ dprintf(CRITICAL, "%s need load addr\n", image_name);
+ return -EINVAL;
+ }
+
+ /* load address determination:
+ * 1. "load" property exist: use address in "load" property
+ * 2. "load" property not exist: use runtime address of "data" property
+ */
+ load_addr = (addr_t)data;
+ if (load_prop) {
+ load_addr = (addr_t)uswap_32(load_prop[0]);
+ if (ac == 2)
+ load_addr = (load_addr << 32) | (addr_t)uswap_32(load_prop[1]);
+#if WITH_KERNEL_VM
+ load_addr = (addr_t)paddr_to_kvaddr(load_addr);
+#endif
+ }
+
+ if (!strcmp((char *)compression, "lz4")) {
+ ret = unlz4(data, size - 4, (void *)(load_addr));
+ if (ret != LZ4_OK) {
+ dprintf(ALWAYS, "lz4 decompress failure\n");
+ return -LZ4_FAIL;
+ }
+ /* In lz4 kernel image, the last four bytes are the uncompressed
+ * kernel image size */
+ size = *(u32 *)(data + size - 4);
+ } else if (!strcmp((char *)compression, "none")) {
+ memmove((void *)(load_addr), data, size);
+ } else {
+ dprintf(CRITICAL, "%s compression does not support\n", image_name);
+ return -EINVAL;
+ }
+
+#if WITH_KERNEL_VM
+ /* always flush cache to PoC */
+ arch_clean_cache_range(load_addr, size);
+#endif
+
+ LTRACEF("[%s] load_addr 0x%lx\n", image_name, load_addr);
+ LTRACEF("[%s] fit = %p\n", image_name, fit);
+ LTRACEF("[%s] data = %p\n", image_name, data);
+ LTRACEF("[%s] size = %zu\n", image_name, size);
+
+ /* return load, load_size and entry address if caller spcified */
+ if (load)
+ *load = load_addr;
+
+ if (load_size)
+ *load_size = size;
+
+ if (entry) {
+ /*
+ * entry address determination:
+ * 1. "entry" property not exist: entry address = load address
+ * 2. "entry" & "load" properties both exist: "entry" property
+ * contains the absolute address of entry, thus
+ * entry address = "entry"
+ * 3. only "entry" property exist: "entry" property contains the
+ * entry offset to load address, thus
+ * entry address = "entry" + load address
+ */
+
+#if WITH_KERNEL_VM
+ load_addr = kvaddr_to_paddr((void *)load_addr);
+#endif
+ entry_addr = load_addr;
+ entry_prop = fdt_getprop(fit, noffset, "entry", &len);
+ if (entry_prop) {
+ entry_addr = (paddr_t)uswap_32(entry_prop[0]);
+ if (ac == 2) {
+ entry_addr = (entry_addr << 32) |
+ (paddr_t)uswap_32(entry_prop[1]);
+ }
+ entry_addr += load_prop ? 0 : load_addr;
+ }
+ *entry = entry_addr;
+
+ LTRACEF("[%s] entry_addr 0x%lx\n", image_name, *entry);
+ }
+
+ return 0;
+}
+
+int fit_load_loadable_image(void *fit, const char *sub_node_name, addr_t *load)
+{
+ int noffset;
+ int ret;
+
+ noffset = fit_get_img_subnode_offset(fit, sub_node_name);
+ if (noffset < 0) {
+ LTRACEF("%s: fit_get_img_subnode_offset fail\n", sub_node_name);
+ return noffset;
+ }
+
+ if (hash_check_enabled()) {
+ ret = fit_image_integrity_verify(fit, noffset);
+ LTRACEF("%s: integrity check %s\n",
+ sub_node_name, ret ? "fail" : "pass");
+ if (ret)
+ return -EACCES;
+ }
+
+ return fit_processing_data(fit, sub_node_name, noffset, load, NULL, NULL);
+}
+
+int fit_conf_verify_sig(const char *conf, void *fit)
+{
+ int ret;
+ int noffset;
+
+ /* get defualt configuration offset (conf@1, conf@2,...or confg@n) */
+ noffset = fit_get_def_cfg_offset(fit, conf);
+ if (noffset < 0)
+ return noffset;
+
+ /* verify config signature */
+ if (rsa_check_enabled()) {
+ ret = fit_verify_sign(fit, noffset);
+ dprintf(ALWAYS, "Verify sign: %s\n", ret ? "fail" : "pass");
+ if (ret)
+ return -EACCES;
+ }
+
+ return 0;
+}
+
+static int fit_image_integrity_check_process(void *arg)
+{
+ int ret;
+ struct verify_data *verify_info;
+
+ verify_info = (struct verify_data *)arg;
+ ret = fit_image_integrity_verify(verify_info->fit_image,
+ verify_info->noffset);
+
+ return ret;
+}
+
+int fit_load_image(const char *conf, const char *img_pro, void *fit,
+ addr_t *load, size_t *load_size, paddr_t *entry,
+ bool need_verified)
+{
+ int noffset, len, cfg_noffset;
+ int ret, rc;
+ const char *image_name;
+ thread_t *integrity_verify_t;
+
+ /* get defualt configuration offset (conf@1, conf@2,...or confg@n) */
+ cfg_noffset = fit_get_def_cfg_offset(fit, conf);
+ if (cfg_noffset < 0)
+ return cfg_noffset;
+
+ /* unit name: fdt@1, kernel@2, ramdisk@3 and so on */
+ image_name = (char *)fdt_getprop(fit, cfg_noffset, img_pro, &len);
+ if (image_name == NULL) {
+ LTRACEF("%s get image name failed\n", img_pro);
+ return -ENOENT;
+ }
+
+ /* get this sub image node offset */
+ noffset = fit_get_img_subnode_offset(fit, image_name);
+ if (noffset < 0) {
+ dprintf(CRITICAL, "get sub image node (%s) failed\n", image_name);
+ return noffset;
+ }
+
+ /* verify integrity of this image */
+ if (hash_check_enabled() && need_verified) {
+#if WITH_SMP
+ struct verify_data verify_info;
+ verify_info.fit_image = fit;
+ verify_info.noffset = noffset;
+
+ integrity_verify_t = thread_create("integrity_verify_t",
+ &fit_image_integrity_check_process, &verify_info,
+ DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+
+ /* Assigned the thread to active cpu */
+ extern __WEAK void plat_mp_assign_workcpu(thread_t *t);
+ plat_mp_assign_workcpu(integrity_verify_t);
+ thread_resume(integrity_verify_t);
+#else
+ ret = fit_image_integrity_verify(fit, noffset);
+ LTRACEF_LEVEL(CRITICAL, "check %s integrity: %s\n",
+ image_name, ret ? "fail" : "pass");
+ if (ret < 0)
+ return -EACCES;
+#endif
+ } /* verify end */
+
+ rc = fit_processing_data(fit, image_name, noffset, load, load_size, entry);
+
+#if WITH_SMP
+ if (hash_check_enabled() && need_verified) {
+ thread_join(integrity_verify_t, &ret, INFINITE_TIME);
+ LTRACEF_LEVEL(CRITICAL, "check %s integrity: %s\n",
+ image_name, ret ? "fail" : "pass");
+ if (ret < 0)
+ return -EACCES;
+ }
+#endif
+
+ return rc;
+}
diff --git a/src/bsp/lk/lib/fit/image_verify.c b/src/bsp/lk/lib/fit/image_verify.c
new file mode 100644
index 0000000..1a96743
--- /dev/null
+++ b/src/bsp/lk/lib/fit/image_verify.c
@@ -0,0 +1,779 @@
+#include <debug.h>
+#include <fit.h>
+#include <malloc.h>
+#include <platform.h>
+#include <libfdt.h>
+#include <blob.h>
+#include <trace.h>
+#include "image.h"
+#include "rsa.h"
+
+#define LOCAL_TRACE 0
+
+int sha256_hash(const void *source, int len, u8 *result);
+int sha512_hash(const void *source, int len, u8 *result);
+
+int calculate_hash_multi_region(const struct image_region region[],
+ int region_count, uint8_t *checksum,
+ int hash_len);
+void mod_exp_65537_mont(uintptr_t *r, const uintptr_t *a,
+ const struct key_prop *pkey);
+
+#define DUMP_DATA 0
+#define debug(fmt, args...)
+#define MAX_HASH_NODES 64
+#define SHA256_SUM_LEN 32
+#define FDT_MAX_DEPTH 32
+#define MAX_REGS(x) (20 +x*7)
+#define IS_NAME_MATCH(x,y) !strncmp((x), (y),strlen(y))
+
+#define SHA512_SUM_LEN 64
+#define PADDING_SIZE 19
+
+#define list_each_subnode(fdt, node, parent) \
+ for (node = fdt_first_subnode(fdt, parent); \
+ node >= 0; \
+ node = fdt_next_subnode(fdt, node))
+
+const uint8_t padding_sha256[PADDING_SIZE] = {
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
+};
+const uint8_t padding_sha512[PADDING_SIZE] = {
+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40
+};
+
+
+struct hash_algo hash_algos[] = {
+ {
+ "sha256",
+ SHA256_SUM_LEN,
+ RSA2048_BYTES,
+ calculate_hash_multi_region,
+ padding_sha256,
+ },
+ {
+ "sha512",
+ SHA512_SUM_LEN,
+ RSA4096_BYTES,
+ calculate_hash_multi_region,
+ padding_sha512,
+ },
+ {
+ "sha256",
+ SHA256_SUM_LEN,
+ RSA4096_BYTES,
+ calculate_hash_multi_region,
+ padding_sha256,
+ },
+ {
+ "sha512",
+ SHA512_SUM_LEN,
+ RSA2048_BYTES,
+ calculate_hash_multi_region,
+ padding_sha512,
+ }
+
+};
+
+struct sig_algo image_sig_algos[] = {
+ {
+ "sha256,rsa2048",
+ &hash_algos[0],
+ rsa_verify,
+ },
+ {
+ "sha512,rsa4096",
+ &hash_algos[1],
+ rsa_verify,
+ },
+ {
+ "sha256,rsa4096",
+ &hash_algos[2],
+ rsa_verify,
+ },
+ {
+ "sha512,rsa2048",
+ &hash_algos[3],
+ rsa_verify,
+ }
+};
+
+static void dump_data(uint8_t *buff,int len)
+{
+ uint i=0;
+
+ for (i=0; i<len; i++) {
+ if ((i%16)==0)
+ LTRACEF("\n");
+ LTRACEF("0x%02x,",buff[i]);
+ }
+}
+
+int rsa_check_enabled(void)
+{
+ return CHECK_RSA;
+}
+
+int hash_check_enabled(void)
+{
+ return CHECK_HASH;
+}
+
+int calculate_hash_multi_region(const struct image_region region[],
+ int region_count, uint8_t *checksum,
+ int hash_len)
+{
+
+ int ret = 0;
+ int32_t i,j,k=0;
+ unsigned long inlen=0;
+ unsigned char *input_data;
+ const unsigned char *tmp_data;
+
+ for (i = 0; i < region_count; i++)
+ inlen+=region[i].size;
+
+ input_data = malloc(inlen);
+ if (!input_data) {
+ LTRACEF("malloc inlen(%lu bytes) failed\n", inlen);
+ return -1;
+ }
+
+ for (i = 0; i < region_count; i++) {
+ tmp_data=region[i].data;
+ for (j = 0; j < region[i].size; j++)
+ input_data[k++]=tmp_data[j];
+ }
+ if (hash_len == SHA256_SUM_LEN) {
+ ret=sha256_hash(input_data, inlen, checksum );
+ } else if (hash_len == SHA512_SUM_LEN) {
+ ret=sha512_hash(input_data, inlen, checksum );
+ } else {
+ LTRACEF(" Unsupported hash len\n");
+ ret = -1;
+ }
+ free(input_data);
+
+ return ret;
+}
+
+int fdt_getval(const void *blob, int node, const char *prop_name,
+ int default_val)
+{
+ const uint *tmp;
+ int get_val=0;
+ int len=0;
+
+ tmp = fdt_getprop(blob, node, prop_name, &len);
+ if ((tmp !=0) && ((unsigned int)len >= sizeof(int))) {
+ get_val = fdt32_to_cpu(tmp[0]);
+ return get_val;
+ }
+ LTRACEF("get %s fail\n",prop_name);
+
+ return default_val;
+}
+
+static void rsa_verify_raw(const uint8_t *bn_n, uint8_t *bn_out,
+ const uint8_t *bn_in)
+{
+ mod_exp_65537_mont((uintptr_t *)bn_out, (const uintptr_t *)bn_in,
+ (const struct key_prop *)bn_n);
+}
+
+void get_pubkey_info(struct key_prop *pubkey, const void *blob,int node,
+ int *len)
+{
+ pubkey->exp_len = sizeof(uint64_t);
+ pubkey->num_bits = fdt_getval(blob, node, BLOB_NBITS_NODE, 0);
+ pubkey->n0inv = *(uint64_t *)fdt_getprop(blob, node, BLOB_N0INV_NODE, NULL);
+ pubkey->rr = fdt_getprop(blob, node, BLOB_RSQU_NODE, NULL);
+ pubkey->modulus = fdt_getprop(blob, node, BLOB_MOD_NODE, NULL);
+ pubkey->public_exponent = fdt_getprop(blob, node, BLOB_EXP_NODE, len);
+ if (!pubkey->public_exponent || (unsigned int)*len < sizeof(uint64_t))
+ pubkey->public_exponent = NULL;
+}
+
+static void rsa_verify_with_pubkey(struct sig_info *info,
+ uint8_t *sig, uint sig_len,
+ int node, uint8_t *buf)
+{
+ int i;
+ int length;
+ int rsa_length = info->algo->hash_info->pad_len;
+ struct key_prop prop;
+ const uint8_t *pubk ,*sign_tmp;
+ const void *blob = info->pubkey;
+ uint8_t __attribute__((aligned(8))) key[rsa_length], sign[rsa_length],
+ plain[rsa_length] ,rr[rsa_length];
+ uint64_t n0inv;
+
+ if (node < 0) {
+ LTRACEF("%s: Skipping invalid node", __func__);
+ return;
+ }
+ get_pubkey_info(&prop,blob,node,&length);
+ pubk=prop.modulus;
+ sign_tmp=sig;
+ for (i = 0; i < rsa_length; i++) {
+ key[rsa_length -i-1] = pubk[i];
+ sign[rsa_length - i -1] = sign_tmp[i];
+ rr[rsa_length - i -1] = *((uint8_t *)prop.rr + i);
+ }
+
+#if DUMP_DATA
+ LTRACEF("start to dump public key ===>>>\n");
+ dump_data(key,rsa_length);
+ LTRACEF("\n end of dump public key <<<===\n");
+#endif
+
+ n0inv=__builtin_bswap64(prop.n0inv);
+ prop.n0inv = n0inv;
+ prop.rr = (const uintptr_t *)rr;
+ prop.modulus = (const uintptr_t *)key;
+
+ mod_exp_65537_mont((uintptr_t *)plain,(const uintptr_t *)sign,&prop);
+
+ for (i = 0; i < rsa_length; i++)
+ buf[rsa_length - i -1] = plain[i];
+#if DUMP_DATA
+ LTRACEF("\nstart to dump rsa_hash ===>>>\n");
+ dump_data(buf,rsa_length);
+ LTRACEF("\nend of dump public rsa_hash <<<===\n");
+#endif
+}
+
+int rsa_verify(struct sig_info *info,
+ const struct fdt_region region[], int region_count,
+ uint8_t *sig, uint sig_len)
+{
+ int ret=0,i;
+ int pad_len;
+ const uint8_t *p,*t;
+ uint8_t buf[sig_len];
+ uint8_t hash[info->algo->hash_info->pad_len];
+ struct image_region hash_region[region_count];
+
+ /* genarte hash region*/
+ for (i = 0; i < region_count; i++) {
+ hash_region[i].data = info->fit_image + region[i].offset;
+ hash_region[i].size = region[i].size;
+ }
+
+
+ if (info->algo->hash_info->hash_len >
+ info->algo->hash_info->pad_len) {
+ LTRACEF("%s: invlaid checksum-algorithm %s for %s\n",
+ __func__, info->algo->hash_info->hash, info->algo->rsa);
+ return -EINVAL;
+ }
+
+ /* checksum hash*/
+ ret = info->algo->hash_info->hash_cal(hash_region, region_count,
+ hash,info->algo->hash_info->hash_len);
+ if (ret < 0) {
+ LTRACEF("%s: Error in checksum calculation\n", __func__);
+ return -EINVAL;
+ }
+
+#if DUMP_DATA
+ LTRACEF("start to dump calculate_hash ===>>\n");
+ dump_data(hash,info->algo->hash_info->pad_len);
+ LTRACEF("\n end of dump calculate_hash <<===\n");
+#endif
+
+ if (info->req_offset != -1) {
+ /*rsa calculate hash*/
+ rsa_verify_with_pubkey(info, sig, sig_len,
+ info->req_offset,&buf[0]);
+
+ /* compare rsa padding. */
+ pad_len = info->algo->hash_info->pad_len -
+ info->algo->hash_info->hash_len - PADDING_SIZE;
+ uint8_t padding[pad_len];
+ memset(padding, 0xff, pad_len);
+ padding[0] = 0x00;
+ padding[1] = 0x01;
+ padding[pad_len -1]=0x00;
+
+ if (memcmp(padding, buf, pad_len)) {
+ LTRACEF("RSA check padding fail !\n");
+ return -EINVAL;
+ }
+
+ p = buf + pad_len;
+ t = &(info->algo->hash_info->hash_padding)[0];
+ if (memcmp(t, p, PADDING_SIZE)) {
+ LTRACEF("RSA check padding fail !\n");
+ return -EINVAL;
+ }
+
+ /* compare calculate hash and rsa hash. */
+ if (memcmp((uint8_t *)buf + pad_len + PADDING_SIZE, hash, sig_len - pad_len - PADDING_SIZE)) {
+ LTRACEF("RSA check hash fail!\n");
+ return -EACCES;
+ }
+
+ if (!ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+int calculate_hash_one_region(const void *data, int data_len, const char *algo,
+ uint8_t *value, int *value_len)
+{
+ if (strcmp(algo, "sha256") == 0) {
+ sha256_hash((unsigned char *)data, data_len,
+ (unsigned char *)value);
+ *value_len = SHA256_SUM_LEN;
+ } else if (strcmp(algo, "sha512") == 0) {
+ sha512_hash((unsigned char *)data, data_len,
+ (unsigned char *)value);
+ *value_len = SHA512_SUM_LEN;
+ } else {
+ LTRACEF(" Unsupported hash alogrithm\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+int fit_get_node_value(const void *fit, int noffset, uint8_t **value,
+ int *value_len)
+{
+ int len;
+
+ *value = (uint8_t *)fdt_getprop(fit, noffset, FDT_VAL_NODE, &len);
+
+ if (*value != NULL) {
+ *value_len = len;
+ return 0;
+ } else {
+ LTRACEF("fit_get_node_value NULL !!\n");
+ *value_len = 0;
+ }
+
+ return -1;
+}
+
+int fit_get_hash_algo(const void *fit, int noffset, char **algo)
+{
+ int len;
+
+ *algo = (char *)fdt_getprop(fit, noffset, FDT_ALGO_NODE, &len);
+ if (*algo != NULL)
+ return 0;
+ else
+ LTRACEF("fdt_getprop algo NULL !!\n");
+
+ return -1;
+}
+
+static int fit_image_check_hash(const void *fit, int noffset, const void *data,
+ uint32_t size)
+{
+ uint8_t value[SHA512_SUM_LEN];
+ int value_len;
+ char *algo;
+ uint8_t *image_hash;
+ int image_hash_len;
+
+ if (fit_get_hash_algo(fit, noffset, &algo)) {
+ LTRACEF("get hash alogrithm fail \n");
+ return -1;
+ }
+
+ if (fit_get_node_value(fit, noffset, &image_hash,&image_hash_len)) {
+ LTRACEF("get hash value fail \n");
+ return -1;
+ }
+
+#if DUMP_DATA
+ LTRACEF("\nstart dump img hash %d===>\n",image_hash_len);
+ dump_data(image_hash,image_hash_len);
+#endif
+
+ if (calculate_hash_one_region(data, (int)size, algo, value, &value_len)) {
+ LTRACEF("calsulate new hash fail !! \n");
+ return -1;
+ }
+
+#if DUMP_DATA
+ LTRACEF("\nstart dump cal hash %d===>\n",value_len);
+ dump_data(value,value_len);
+#endif
+
+ if (value_len != image_hash_len) {
+ LTRACEF("hash length error ! \n");
+ return -1;
+ }
+
+ if (memcmp(value, image_hash, value_len) != 0) {
+ LTRACEF("compare hash value fail !! \n");
+ return -1;
+ }
+
+ LTRACEF("check integrity success! \n");
+ return 0;
+}
+
+static int fit_verify_prepare(struct sig_info *sign_info,
+ const void *fit, int noffset,
+ int required_keynode)
+{
+ char *algo_name;
+
+ if (fit_get_hash_algo(fit, noffset, &algo_name))
+ return -1;
+
+ memset(sign_info, '\0', sizeof(*sign_info));
+ sign_info->fit_image = (void *)fit;
+ sign_info->algo = image_get_sig_algo(algo_name);
+ sign_info->pubkey = &blob[0];
+ sign_info->req_offset = required_keynode;
+ LTRACEF("%s\n", algo_name);
+
+ if (!sign_info->algo)
+ return -1;
+
+ return 0;
+}
+
+int fit_image_integrity_verify(const void *fit, int image_noffset)
+{
+ const void *data;
+ int noffset;
+ uint32_t size;
+
+ /* Get image data and data length */
+ if (fit_image_get_data(fit, image_noffset, &data, &size)) {
+ LTRACEF("fit_image_get_data fail ! \n");
+ return -EACCES;
+ }
+ /* Process all hash subnodes of the component image node */
+ list_each_subnode(fit, noffset, image_noffset) {
+ const char *node_name = fit_get_name(fit, noffset, NULL);
+ if (IS_NAME_MATCH(node_name, FDT_HASH_NODE)) {
+ if (fit_image_check_hash(fit, noffset, data, size))
+ return -EACCES;
+ }
+ }
+
+ return 0;
+}
+
+struct sig_algo *image_get_sig_algo(const char *name)
+{
+ uint i;
+
+ for (i = 0; i < ARRAY_SIZE(image_sig_algos); i++) {
+ if (!strcmp(image_sig_algos[i].rsa, name))
+ return &image_sig_algos[i];
+ }
+
+ return NULL;
+}
+
+static int fit_get_hashed_node_name(const void *fit, int noffset,
+ int conf_noffset, char *nod_name[])
+{
+ int prop_len;
+ int i;
+ const char *prop_start, *prop_end, *prop_name;
+ const char *conf_name;
+ char *conf_path;
+ size_t conf_path_len;
+ bool conf_hashed;
+
+ prop_start = fdt_getprop(fit, noffset, FDT_HASHED_NODE, &prop_len);
+ prop_end = prop_start ? prop_start + prop_len : prop_start;
+ prop_name = prop_start;
+
+ conf_name = fit_get_name(fit, conf_noffset, NULL);
+ if (conf_name == NULL)
+ return -1;
+
+ conf_path_len = strlen(FIT_CONFIGS_PATH) + 1 + strlen(conf_name) + 1;
+ conf_path = malloc(conf_path_len);
+ if (conf_path == NULL)
+ return -1;
+
+ snprintf(conf_path, conf_path_len, "%s/%s", FIT_CONFIGS_PATH, conf_name);
+
+ i = 0;
+ conf_hashed = false;
+ while (prop_name < prop_end) {
+ if (!conf_hashed && !strncmp(conf_path, prop_name, conf_path_len - 1))
+ conf_hashed = true;
+ nod_name[i] = (char *)prop_name;
+ prop_name += strlen(prop_name) + 1;
+ i++;
+ }
+ free(conf_path);
+
+ return conf_hashed ? i : -1;
+}
+
+static int is_recorded_string(const char *string, char *const recorder[],
+ int rec_num)
+{
+ int i;
+
+ for (i = 0; i < rec_num; i++) {
+ if (!strcmp(recorder[i], string))
+ return 1;
+ }
+
+ return 0;
+}
+
+#define get_base(x) fdt_off_dt_struct(x)
+
+int fdt_prop_check(const void *fit, uint offset, char *const invalid_list[],
+ int invalid_num, int default_val)
+{
+ int def_val = 0;
+ const char *string;
+ const struct fdt_property *property;
+
+ if (default_val >= 2)
+ def_val = 1;
+ property = fdt_get_property_by_offset(fit, offset, NULL);
+ string = fdt_string(fit, fdt32_to_cpu(property->nameoff));
+ if (is_recorded_string(string, invalid_list, invalid_num))
+ def_val = 0;
+
+ return def_val;
+}
+
+int fdt_check_range(const void *fit, int reg_num,
+ int max_reg_num,uint nextoffset)
+{
+ if (nextoffset != fdt_size_dt_struct(fit))
+ return -FDT_ERR_BADLAYOUT;
+
+ if (reg_num >= max_reg_num)
+ return -FDT_ERR_BADVALUE;
+
+ return 0;
+}
+
+int fdt_parsing_regions(const void *fit, char *const record_list[],
+ int record_num, char *const property_list[],
+ int property_num, struct fdt_region region[],
+ int max_regions_num)
+{
+ int stack[FDT_MAX_DEPTH];
+ char path[200] = { '\0' };
+ int path_len = sizeof(path);
+ int path_level = -1;
+ char *ppath;
+ int nextoffset = 0;
+ uint previousoffset = 0;
+ uint32_t tag;
+ int region_num = 0;
+ int region_offset = -1;
+ int record = 0;
+ ppath = path;
+
+ do {
+ const char *node_name = NULL;
+ int node_name_len = 0;
+ int is_region_recorded = 0;
+ uint stopoffset = 0;
+ uint startoffset = 0;
+
+ startoffset = nextoffset;
+ tag = fdt_next_tag(fit, startoffset, &nextoffset);
+ stopoffset = nextoffset;
+
+ /* Start of node*/
+ if (tag == FDT_BEGIN_NODE) {
+ path_level++;
+ if (path_level == FDT_MAX_DEPTH)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ node_name = fdt_get_name(fit, startoffset, &node_name_len);
+ if (ppath - path + 2 + node_name_len >= path_len)
+ return -FDT_ERR_NOSPACE;
+ if (ppath != path + 1)
+ *ppath++ = '/';
+ strncpy(ppath, node_name, node_name_len + 1);
+ ppath += node_name_len;
+ stack[path_level] = record;
+ if (record == 1)
+ stopoffset = startoffset;
+ if (is_recorded_string(path, record_list, record_num))
+ record = 2;
+ else if (record)
+ record--;
+ else
+ stopoffset = startoffset;
+ is_region_recorded = record;
+ } else if (tag == FDT_END_NODE) {
+ /* End of node */
+ is_region_recorded = record;
+ record = stack[path_level--];
+ for (; ppath > path;) {
+ if (*--ppath == '/') {
+ *ppath = '\0';
+ break;
+ }
+ }
+ } else if (tag == FDT_PROP) {
+ /* Property node: contain: name, size, content */
+ is_region_recorded = fdt_prop_check(fit, startoffset, property_list,
+ property_num, record);
+ stopoffset = startoffset;
+ } else if (tag == FDT_NOP) {
+ /* nop node*/
+ stopoffset = startoffset;
+ is_region_recorded = record >= 2;
+ } else if (tag == FDT_END) {
+ /* End of fdt */
+ is_region_recorded = 1;
+ }
+
+ if (is_region_recorded && region_offset == -1) {
+ if (region_num > 0) {
+ previousoffset = region[region_num - 1].offset +
+ region[region_num - 1].size - get_base(fit);
+ if ((region_num <= max_regions_num) &&
+ (startoffset == previousoffset))
+ region_offset = region[--region_num].offset - get_base(fit);
+ }
+
+ if (region_offset == -1)
+ region_offset = startoffset;
+ }
+
+ if (!is_region_recorded && region_offset != -1) {
+ if (region_num < max_regions_num) {
+ region[region_num].offset = get_base(fit) + region_offset;
+ region[region_num].size = stopoffset - region_offset;
+ }
+ region_num++;
+ region_offset = -1;
+ }
+ } while (tag != FDT_END);
+
+ //end handle
+ if (region_num < max_regions_num) {
+ region[region_num].offset = get_base(fit) + region_offset;
+ region[region_num].size = nextoffset - region_offset;
+ region_num++;
+ }
+
+ if (fdt_check_range(fit, region_num, max_regions_num, nextoffset))
+ return 0;
+
+ return region_num;
+}
+
+static int fit_check_sign(const void *fit, int noffset, int conf_noffset,
+ int required_keynode)
+{
+ int node_num;
+ int image_sign_len;
+ uint8_t *image_sign;
+ const uint32_t *strings;
+ struct sig_info sign_info;
+ const char *tmp_data = "data" ;
+ char *const exc_prop[] = {(char *const)tmp_data};
+ char *node_name[MAX_HASH_NODES];
+
+ /* get sign info and sign image */
+ if (fit_verify_prepare(&sign_info, fit, noffset, required_keynode))
+ return -1;
+
+ if (fit_get_node_value(fit, noffset, &image_sign, &image_sign_len))
+ return -1;
+
+#if DUMP_DATA
+ LTRACEF("\nstart to dump sign (len=%d) ===>>\n", image_sign_len);
+ dump_data(image_sign, image_sign_len);
+ LTRACEF("\n end of dump sign <<====\n");
+#endif
+
+ /* get node name of fdt image */
+ node_num = fit_get_hashed_node_name(fit, noffset, conf_noffset, node_name);
+ if (node_num < 0)
+ return -1;
+
+ /* parsing regions */
+ struct fdt_region fdt_regions[MAX_REGS(node_num)];
+
+ node_num = fdt_parsing_regions(fit, node_name, node_num,
+ exc_prop, ARRAY_SIZE(exc_prop),
+ fdt_regions, (MAX_REGS(node_num) - 1));
+ if (node_num < 0)
+ return -1;
+
+ strings = fdt_getprop(fit, noffset, FDT_HASHED_STR, NULL);
+ if (strings) {
+ fdt_regions[node_num].offset = fdt_off_dt_strings(fit) +
+ fdt32_to_cpu(strings[0]);
+ fdt_regions[node_num].size = fdt32_to_cpu(strings[1]);
+ node_num++;
+ }
+
+ /* signature verify */
+ if (sign_info.algo->sig_verify(&sign_info, fdt_regions, node_num,
+ image_sign, image_sign_len)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fit_verify_configed_sign(const void *fit, int conf_noffset,
+ const void *sig_blob, int sig_offset)
+{
+ int noffset;
+ int ret = -1;
+
+ list_each_subnode(fit, noffset, conf_noffset) {
+ const char *node_name = fit_get_name(fit, noffset, NULL);
+ if (IS_NAME_MATCH(node_name,FDT_SIG_NODE)) {
+ ret = fit_check_sign(fit, noffset, conf_noffset, sig_offset);
+ LTRACEF("check sign %s!\n", ret ? "fail" : "pass");
+ if (ret == 0)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+int fit_verify_sign(const void *fit, int conf_noffset)
+{
+ const char *req_node = NULL;
+ int ret;
+ int noffset;
+ int sig_node;
+ const void *sig_blob = &blob[0];
+
+ sig_node = fdt_subnode_offset(sig_blob, 0, FDT_SIG_NODE);
+ if (sig_node < 0) {
+ LTRACEF(" No sign node (signature): %s\n",fdt_strerror(sig_node));
+ return -1;
+ }
+
+ list_each_subnode(sig_blob, noffset, sig_node) {
+ req_node = fdt_getprop(sig_blob, noffset, BLOB_REQ_NODE, NULL);
+ if ((req_node !=NULL)&&(!strcmp(req_node, "conf"))) {
+ ret = fit_verify_configed_sign(fit, conf_noffset, sig_blob,noffset);
+ if (ret) {
+ LTRACEF("Failed to verify '%s'\n",
+ fit_get_name(sig_blob, noffset, NULL));
+ }
+ return ret;
+ }
+ }
+
+ return -1;
+}
diff --git a/src/bsp/lk/lib/fit/include/fit.h b/src/bsp/lk/lib/fit/include/fit.h
new file mode 100644
index 0000000..39b307a
--- /dev/null
+++ b/src/bsp/lk/lib/fit/include/fit.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#pragma once
+
+#include <stdbool.h>
+#include <sys/types.h>
+
+/**
+ * fit_get_image() - load fit image from a partition
+ *
+ * the function will use bio to access a partition from a storage and
+ * check fdt header. If pass, allocate memory buffer to read the fit image
+ * to load_buf
+ *
+ * @label: partition name
+ * @load_buf: pointer to buffer pointer, the address of allocated memory
+ * buffer with fit image loaded was passing back to the caller
+ * via this argument.
+ *
+ * returns:
+ * 0, on success
+ * otherwise, on failure
+ *
+ */
+int fit_get_image(const char *label, void **load_buf);
+
+/**
+ * fit_image_get_data() - get data property of a subimage node
+ * @fit: fit image start address
+ * @noffset: the offset to the subimage node
+ * @data: return data pointer
+ * @size: return data size
+ *
+ * returns:
+ * 0, on success
+ * otherwise, on failure
+ */
+int fit_image_get_data(const void *fit, int noffset,
+ const void **data, uint32_t *size);
+/**
+ * fit_conf_verify_sig() - verify fit configuration signature
+ *
+ * @conf: configuration name
+ * @fit: fit image start address
+ *
+ * returns:
+ * 0, on success
+ * otherwise, on failure
+ */
+int fit_conf_verify_sig(const char *conf, void *fit);
+
+/**
+ * fit_load_image() - load fit image to proper address
+ *
+ * This checks FIT configuration to find sub-image nodes image
+ * and load the image to right address
+ *
+ * @conf: configuration name
+ * @img_pro: image property name
+ * @fit: fit image start address
+ * @load: returned load address
+ * @load_size: returned loaded raw image size
+ * @entry: returned entry address
+ * @need_verified: whether to check image integrity
+ *
+ * returns:
+ * 0, on success
+ * otherwise, on failure
+ *
+ */
+int fit_load_image(const char *conf, const char *img_pro, void *fit,
+ addr_t *load, size_t *load_size, paddr_t *entry,
+ bool need_verified);
+
+/**
+ * fit_load_loadable_image() - load "loadable" images to "load" address
+ *
+ * This function finds "sub_node_name" loadable image nodes, do integrity check
+ * per hash_check_enabled(), and load images to "load" address.
+ *
+ * @fit: fit image start address
+ * @sub_node_name: loadable image subnode name
+ * @load: returned loadable image load address
+ *
+ * return:
+ * 0: success
+ * otherwise: failure error code
+ *
+ */
+int fit_load_loadable_image(void *fit, const char *sub_node_name, addr_t *load);
diff --git a/src/bsp/lk/lib/fit/include/image.h b/src/bsp/lk/lib/fit/include/image.h
new file mode 100644
index 0000000..ff5d14c
--- /dev/null
+++ b/src/bsp/lk/lib/fit/include/image.h
@@ -0,0 +1,92 @@
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+#include <libfdt.h>
+#include <sys/types.h>
+
+#define SPEW_D 0
+#define FIT_MAX_HASH_LEN 32
+
+#ifndef CHUNKSZ_SHA1
+#define CHUNKSZ_SHA1 (64 * 1024)
+#endif
+
+#define IMAGE_ENABLE_TIMESTAMP 0
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define FIT_IMAGES_PATH "/images"
+#define FIT_CONFIGS_PATH "/configurations"
+
+/* hash/signature node */
+#define FDT_HASH_NODE "hash"
+#define FDT_ALGO_NODE "algo"
+#define FDT_VAL_NODE "value"
+#define FDT_SIG_NODE "signature"
+#define FDT_HASHED_NODE "hashed-nodes"
+#define FDT_HASHED_STR "hashed-strings"
+
+/*blob node */
+#define BLOB_REQ_NODE "required"
+#define BLOB_NBITS_NODE "rsa,num-bits"
+#define BLOB_N0INV_NODE "rsa,n0-inverse"
+#define BLOB_RSQU_NODE "rsa,r-squared"
+#define BLOB_MOD_NODE "rsa,modulus"
+#define BLOB_EXP_NODE "rsa,exponent"
+
+/* image node */
+#define FDT_DATA_NODE "data"
+
+struct fdt_region {
+ int offset;
+ int size;
+};
+
+struct image_region {
+ const void *data;
+ int size;
+};
+
+struct sig_info {
+ void *fit_image;
+ const void *pubkey;
+ struct sig_algo *algo;
+ int req_offset;
+};
+
+struct verify_data {
+ const void *fit_image;
+ int noffset;
+};
+
+struct hash_algo {
+ const char *hash;
+ const int hash_len;
+ const int pad_len;
+ int (*hash_cal)(const struct image_region region[],int region_count, uint8_t *checksum, int hash_len);
+ const uint8_t *hash_padding;
+};
+
+struct sig_algo {
+ const char *rsa;
+ struct hash_algo *hash_info;
+ int (*sig_verify)(struct sig_info *info,
+ const struct fdt_region region[],
+ int region_count, uint8_t *sig, uint sig_len);
+
+};
+
+static inline const char *fit_get_name(const void *fit_hdr,
+ int noffset, int *len)
+{
+ return fdt_get_name(fit_hdr, noffset, len);
+}
+
+struct sig_algo *image_get_sig_algo(const char *name);
+
+int fit_image_integrity_verify(const void *fit, int image_noffset);
+
+int rsa_check_enabled(void);
+int hash_check_enabled(void);
+int fit_verify_sign(const void *fit, int conf_noffset);
+
+#endif
diff --git a/src/bsp/lk/lib/fit/include/rsa.h b/src/bsp/lk/lib/fit/include/rsa.h
new file mode 100644
index 0000000..4247b53
--- /dev/null
+++ b/src/bsp/lk/lib/fit/include/rsa.h
@@ -0,0 +1,33 @@
+#ifndef _RSA_H
+#define _RSA_H
+
+#include <errno.h>
+#include "image.h"
+
+#define RSA2048_BYTES (2048 / 8)
+#define RSA4096_BYTES (4096 / 8)
+
+/* This is the minimum/maximum key size we support, in bits */
+#define RSA_MIN_KEY_BITS 2048
+#define RSA_MAX_KEY_BITS 4096
+
+/* This is the maximum signature length that we support, in bits */
+#define RSA_MAX_SIG_BITS 4096
+
+struct key_prop {
+
+ const void *rr;
+ const void *modulus;
+ const void *public_exponent;
+ uint64_t n0inv;
+ int num_bits;
+ uint32_t exp_len;
+};
+
+int rsa_verify(struct sig_info *info,
+ const struct fdt_region region[], int region_count,
+ uint8_t *sig, uint sig_len);
+void get_pubkey_info(struct key_prop *pubkey, const void *blob,int node,
+ int *len);
+
+#endif
diff --git a/src/bsp/lk/lib/fit/rules.mk b/src/bsp/lk/lib/fit/rules.mk
new file mode 100644
index 0000000..cd99956
--- /dev/null
+++ b/src/bsp/lk/lib/fit/rules.mk
@@ -0,0 +1,21 @@
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+MODULE_BUILDDIR := $(call TOBUILDDIR,$(MODULE))
+MODULE_INCLUDES += $(MODULE_BUILDDIR)/../../../include
+
+MODULE_DEPS += \
+ lib/bio \
+ lib/lz4 \
+ lib/mempool \
+ lib/sha256 \
+ lib/sha512 \
+ lib/rsa
+
+MODULE_SRCS += \
+ $(LOCAL_DIR)/fit.c \
+ $(LOCAL_DIR)/image_verify.c
+
+MODULE_COMPILEFLAGS += -Wno-sign-compare
+
+include make/module.mk