[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