diff --git a/arch/arm/boot/dts/amlogic/meson8b_m200.dts b/arch/arm/boot/dts/amlogic/meson8b_m200.dts index 0a9ad1c28d75..8f8e40b9c8f6 100644 --- a/arch/arm/boot/dts/amlogic/meson8b_m200.dts +++ b/arch/arm/boot/dts/amlogic/meson8b_m200.dts @@ -224,93 +224,48 @@ compatible = "amlogic, unifykey"; status = "ok"; - unifykey-num = <14>; + unifykey-num = <6>; unifykey-index-0 = <&keysn_0>; unifykey-index-1 = <&keysn_1>; unifykey-index-2 = <&keysn_2>; unifykey-index-3 = <&keysn_3>; unifykey-index-4 = <&keysn_4>; unifykey-index-5 = <&keysn_5>; - unifykey-index-6 = <&keysn_6>; - unifykey-index-7 = <&keysn_7>; - unifykey-index-8 = <&keysn_8>; - unifykey-index-9 = <&keysn_9>; - unifykey-index-10= <&keysn_10>; - unifykey-index-11= <&keysn_11>; - unifykey-index-12= <&keysn_12>; - unifykey-index-13= <&keysn_13>; keysn_0: key_0{ key-name = "usid"; - key-device = "normal"; + key-device = "nandkey"; + key-dataformat = "allascii"; key-permit = "read","write","del"; }; keysn_1:key_1{ key-name = "mac"; - key-device = "normal"; + key-device = "nandkey"; + key-dataformat = "hexdata"; key-permit = "read","write","del"; }; keysn_2:key_2{ key-name = "hdcp"; - key-device = "secure"; - key-type = "sha1"; + key-device = "nandkey"; + key-dataformat = "hexdata"; key-permit = "read","write","del"; }; keysn_3:key_3{ key-name = "secure_boot_set"; - key-device = "efuse"; - key-permit = "write"; + key-device = "efusekey"; + key-dataformat = "hexdata"; + key-permit = "read","write"; }; keysn_4:key_4{ key-name = "mac_bt"; - key-device = "normal"; + key-device = "nandkey"; + key-dataformat = "hexdata"; key-permit = "read","write","del"; - key-type = "mac"; }; keysn_5:key_5{ key-name = "mac_wifi"; - key-device = "normal"; - key-permit = "read","write","del"; - key-type = "mac"; - }; - keysn_6:key_6{ - key-name = "hdcp2_tx"; - key-device = "normal"; - key-permit = "read","write","del"; - }; - keysn_7:key_7{ - key-name = "hdcp2_rx"; - key-device = "normal"; - key-permit = "read","write","del"; - }; - keysn_8:key_8{ - key-name = "widevinekeybox"; - key-device = "secure"; - key-permit = "read","write","del"; - }; - keysn_9:key_9{ - key-name = "deviceid"; - key-device = "normal"; - key-permit = "read","write","del"; - }; - keysn_10:key_10{ - key-name = "hdcp22_fw_private"; - key-device = "secure"; - key-permit = "read","write","del"; - }; - keysn_11:key_11{ - key-name = "PlayReadykeybox25"; - key-device = "secure"; - key-permit = "read","write","del"; - }; - keysn_12:key_12{ - key-name = "prpubkeybox";// PlayReady - key-device = "secure"; - key-permit = "read","write","del"; - }; - keysn_13:key_13{ - key-name = "prprivkeybox";// PlayReady - key-device = "secure"; + key-device = "nandkey"; + key-dataformat = "hexdata"; key-permit = "read","write","del"; }; };//End unifykey diff --git a/drivers/amlogic/unifykey/unifykey.c b/drivers/amlogic/unifykey/unifykey.c index 787900d75f54..56313491f93c 100644 --- a/drivers/amlogic/unifykey/unifykey.c +++ b/drivers/amlogic/unifykey/unifykey.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "unifykey.h" #include "amlkey_if.h" @@ -61,6 +62,30 @@ static int init_flag; static int module_init_flag; static int lock_flag; +static char hex_to_asc(char para) +{ + if (para >= 0 && para <= 9) + para = para+'0'; + else if (para >= 0xa && para <= 0xf) + para = para+'a'-0xa; + + return para; +} + +static char asc_to_hex(char para) +{ + if (para >= '0' && para <= '9') + para = para-'0'; + else if (para >= 'a' && para <= 'f') + para = para-'a'+0xa; + else if (para >= 'A' && para <= 'F') + para = para-'A'+0xa; + + return para; +} + + + static int key_storage_init(char *buf, unsigned int len) { int encrypt_type; @@ -315,6 +340,8 @@ int key_unify_write(char *keyname, unsigned char *keydata, int err = 0; int attr; struct key_item_t *unifykey; + unsigned char *fmt_data; + int i, j; unifykey = unifykey_find_item_by_name(keyname); if (unifykey == NULL) { @@ -340,8 +367,24 @@ int key_unify_write(char *keyname, unsigned char *keydata, KEY_UNIFY_ATTR_SECURE : 0); attr |= (unifykey->attr & KEY_UNIFY_ATTR_ENCRYPT_MASK) ? KEY_UNIFY_ATTR_ENCRYPT : 0; - err = key_storage_write(keyname, keydata, - datalen, attr); + if (is_meson_m8b_cpu() && + (unifykey->df != KEY_M_HEXASCII)) { + fmt_data = kmalloc(datalen*2+1, GFP_KERNEL); + if (!fmt_data) + return -ENOMEM; + memset(fmt_data, 0x00, datalen*2+1); + for (i = 0, j = 0; i < datalen; i++) { + fmt_data[j++] = hex_to_asc(( + keydata[i]>>4) & 0x0f); + fmt_data[j++] = hex_to_asc(( + keydata[i]) & 0x0f); + } + err = key_storage_write(keyname, fmt_data, + strlen(fmt_data), attr); + kfree(fmt_data); + } else + err = key_storage_write(keyname, keydata, + datalen, attr); break; case KEY_M_UNKNOWN_DEV: default: @@ -367,6 +410,8 @@ int key_unify_read(char *keyname, unsigned char *keydata, { int err = 0; struct key_item_t *unifykey; + unsigned char *fmt_data; + int i, j; if (!keydata) { pr_err("%s:%d, keydata is NULL\n", @@ -398,8 +443,26 @@ int key_unify_read(char *keyname, unsigned char *keydata, datalen, reallen, 1); break; case KEY_M_NORMAL: - err = key_storage_read(keyname, keydata, - datalen, reallen, 0); + if (is_meson_m8b_cpu() && + (unifykey->df != KEY_M_HEXASCII)) { + fmt_data = kmalloc(datalen*2+1, GFP_KERNEL); + if (!fmt_data) + return -ENOMEM; + memset(fmt_data, 0x00, datalen*2+1); + err = key_storage_read(keyname, fmt_data, + datalen*2, reallen, 0); + if (err != 0) { + kfree(fmt_data); + return err; + } + for (i = 0, j = 0; i < *reallen/2; i++, j += 2) + keydata[i] = (((asc_to_hex(fmt_data[j] + ))<<4) | (asc_to_hex(fmt_data[j+1]))); + *reallen = *reallen/2; + kfree(fmt_data); + } else + err = key_storage_read(keyname, keydata, + datalen, reallen, 0); break; case KEY_M_UNKNOWN_DEV: default: @@ -459,6 +522,9 @@ int key_unify_size(char *keyname, unsigned int *reallen) break; case KEY_M_NORMAL: *reallen = key_storage_size(keyname); + if (is_meson_m8b_cpu() && + (unifykey->df != KEY_M_HEXASCII)) + *reallen = *reallen/2; break; case KEY_M_UNKNOWN_DEV: default: @@ -1106,6 +1172,7 @@ static ssize_t write_store(struct class *cla, unsigned char *keydata = NULL; size_t key_len = 0; + if (curkey != NULL) { keydata = kzalloc(count, GFP_KERNEL); diff --git a/drivers/amlogic/unifykey/unifykey.h b/drivers/amlogic/unifykey/unifykey.h index 4d56029c65d4..d0f90537dd7b 100644 --- a/drivers/amlogic/unifykey/unifykey.h +++ b/drivers/amlogic/unifykey/unifykey.h @@ -36,6 +36,14 @@ enum key_manager_dev_e { KEY_M_MAX_DEV, }; +/*key data format*/ +enum key_manager_df_e { + KEY_M_HEXDATA = 0, + KEY_M_HEXASCII = 1, + KEY_M_ALLASCII = 2, + KEY_M_MAX_DF = 0xff, +}; + enum key_manager_permit_e { KEY_M_PERMIT_READ = (1<<0), KEY_M_PERMIT_WRITE = (1<<1), @@ -47,7 +55,13 @@ enum key_manager_flag_e { KEY_M_FLAG_EMPTY = (0<<0), KEY_M_FLAG_EXSIT = (1<<0), }; + +#ifdef CONFIG_MACH_MESON8B +#define KEY_UNIFY_NAME_LEN 16 +#else #define KEY_UNIFY_NAME_LEN 48 +#endif + /* for ioctrl transfer parameters. */ struct key_item_info_t { unsigned int id; @@ -67,7 +81,7 @@ struct key_item_t { char name[KEY_UNIFY_NAME_LEN]; int id; unsigned int dev; /* key save in device //efuse, */ - /* unsigned int df; */ + unsigned int df; unsigned int permit; int attr; int reserve; diff --git a/drivers/amlogic/unifykey/unifykey_dts.c b/drivers/amlogic/unifykey/unifykey_dts.c index 167b405ba726..86e49b925819 100644 --- a/drivers/amlogic/unifykey/unifykey_dts.c +++ b/drivers/amlogic/unifykey/unifykey_dts.c @@ -32,6 +32,11 @@ #define KEY_DEV_NORMAL "normal" #define KEY_DEV_SECURE "secure" +/* compatibility for old names */ +#define KEY_COMP_DEV_EFUSE "efusekey" +#define KEY_COMP_DEV_NORMAL "nandkey" +#define KEY_COMP_DEV_SECURE "secureskey" + /* permision */ #define KEY_PERMIT_READ "read" #define KEY_PERMIT_WRITE "write" @@ -172,11 +177,14 @@ static int unifykey_item_parse_dt(struct device_node *node, int id) goto exit; } if (propname) { - if (strcmp(propname, KEY_DEV_EFUSE) == 0) + if (strcmp(propname, KEY_DEV_EFUSE) == 0 || + strcmp(propname, KEY_COMP_DEV_EFUSE) == 0) temp_item->dev = KEY_M_EFUSE; - else if (strcmp(propname, KEY_DEV_NORMAL) == 0) + else if (strcmp(propname, KEY_DEV_NORMAL) == 0 || + strcmp(propname, KEY_COMP_DEV_NORMAL) == 0) temp_item->dev = KEY_M_NORMAL; - else if (strcmp(propname, KEY_DEV_SECURE) == 0) + else if (strcmp(propname, KEY_DEV_SECURE) == 0 || + strcmp(propname, KEY_COMP_DEV_SECURE)) temp_item->dev = KEY_M_SECURE; else temp_item->dev = KEY_M_UNKNOWN_DEV; @@ -191,6 +199,26 @@ static int unifykey_item_parse_dt(struct device_node *node, int id) temp_item->permit |= KEY_M_PERMIT_DEL; temp_item->id = id; + if (is_meson_m8b_cpu()) { + temp_item->df = KEY_M_MAX_DF; + ret = of_property_read_string(node, "key-dataformat", + &propname); + if (ret < 0) { + ret = -EINVAL; + goto exit; + } + if (propname) { + if (strcmp(propname, "hexdata") == 0) + temp_item->df = KEY_M_HEXDATA; + else if (strcmp(propname, "hexascii") == 0) + temp_item->df = KEY_M_HEXASCII; + else if (strcmp(propname, "allascii") == 0) + temp_item->df = KEY_M_ALLASCII; + else + temp_item->df = KEY_M_MAX_DF; + } + } + temp_item->attr = 0; ret = of_property_read_string(node, "key-encrypt", &propname); if (ret < 0) diff --git a/drivers/amlogic/unifykey/v7/key_storage/Makefile b/drivers/amlogic/unifykey/v7/key_storage/Makefile index 15a06f9e83f0..9e46935acaa3 100644 --- a/drivers/amlogic/unifykey/v7/key_storage/Makefile +++ b/drivers/amlogic/unifykey/v7/key_storage/Makefile @@ -1,4 +1,9 @@ # # Makefile for Meson m8b series unifykey. # -obj-$(CONFIG_AMLOGIC_V7_UNIFYKEY) += crypto_api.o storage.o storage_util.o tlv.o key_service_routine.o storage_apis.o storage_util.o +obj-$(CONFIG_AMLOGIC_V7_UNIFYKEY) += crypto_api.o \ + storage.o \ + storage_util.o \ + key_service_routine.o \ + storage_apis.o \ + storage_util.o diff --git a/drivers/amlogic/unifykey/v7/key_storage/crypto_api.c b/drivers/amlogic/unifykey/v7/key_storage/crypto_api.c index 87de64e21b4f..0a368e2a855c 100644 --- a/drivers/amlogic/unifykey/v7/key_storage/crypto_api.c +++ b/drivers/amlogic/unifykey/v7/key_storage/crypto_api.c @@ -18,53 +18,60 @@ #include #include #include +#include #include #include "crypto_api.h" -static u8 pkey[32] = {0xc1, 0xb2, 0x33, 0x34, 5, 6, 7, 8, - 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x11, - 0xc3, 0xb4, 0x32, 0x34, 5, 6, 7, 8, - 9, 0xa, 0xb, 0xc1, 0xd, 0xe1, 0xf2, 0x12}; + +static u8 const fixed_iv[16] = {0xAD, 0x93, 0x00, 0xC4, + 0x8E, 0x50, 0x20, 0xC5, + 0x3F, 0xBF, 0x23, 0x32, + 0x80, 0x5A, 0xC6, 0xDF}; +static u8 const fixed_key[32] = {0x2F, 0x7D, 0x49, 0xD9, + 0x15, 0x8B, 0x7F, 0x04, + 0x2C, 0x80, 0xB0, 0x62, + 0x78, 0x25, 0x8D, 0x9C, + 0x13, 0x22, 0x02, 0x4A, + 0x55, 0x23, 0xBB, 0xCB, + 0xF1, 0xFB, 0x2A, 0xCC, + 0xBB, 0x95, 0xF4, 0x50}; + + + +// AES-256-CBC int do_aes_internal(unsigned char enc_flag, unsigned char *in, int in_len, unsigned char *out, int *out_len) { - int ret = -1; - int load_len = 0; - unsigned char blk_buf[64]; - struct crypto_cipher *tfm; + int ret = -1; + struct crypto_blkcipher *tfm; + struct blkcipher_desc desc; + struct scatterlist sg_in; + struct scatterlist sg_out; if (!in || !out || !out_len) return ret; - memset(out, 0x00, in_len); - - tfm = crypto_alloc_cipher("aes", 4, CRYPTO_ALG_ASYNC); + tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(tfm)) return PTR_ERR(tfm); + desc.tfm = tfm; + desc.flags = 0x00; - crypto_cipher_setkey(tfm, pkey, 32); + sg_init_one(&sg_in, in, in_len); + sg_init_one(&sg_out, out, in_len); + crypto_blkcipher_setkey(tfm, fixed_key, 32); + crypto_blkcipher_set_iv(tfm, fixed_iv, 16); - load_len = AES_BLOCK_SIZE; - *out_len = 0; + if (enc_flag) + crypto_blkcipher_encrypt(&desc, &sg_out, &sg_in, sg_in.length); + else + crypto_blkcipher_decrypt(&desc, &sg_out, &sg_in, sg_in.length); - do { - memset(blk_buf, 0, sizeof(blk_buf)); - memcpy(blk_buf, in + *out_len, load_len); - - if (enc_flag) - crypto_cipher_encrypt_one(tfm, out + *out_len, blk_buf); - else - crypto_cipher_decrypt_one(tfm, out + *out_len, blk_buf); - *out_len += load_len; - - if (*out_len + load_len > in_len) - load_len = in_len - *out_len; - } while (*out_len != in_len); + *out_len = sg_out.length; + crypto_free_blkcipher(tfm); ret = 0; - - crypto_free_cipher(tfm); return ret; } diff --git a/drivers/amlogic/unifykey/v7/key_storage/storage.c b/drivers/amlogic/unifykey/v7/key_storage/storage.c index 2bd231c6b59f..ce6114e10c68 100644 --- a/drivers/amlogic/unifykey/v7/key_storage/storage.c +++ b/drivers/amlogic/unifykey/v7/key_storage/storage.c @@ -17,21 +17,27 @@ #include #include +#include +#include #include "storage.h" #include "storage_util.h" #include "storage_data.h" #include "storage_def.h" #include "crypto_api.h" +static int emmc_key_transfer(u8 *buf, u32 *value, u32 len, u32 direct); +static uint32_t emmckey_checksum(uint8_t *buf, uint32_t length); + static void storage_hash(uint8_t *input, uint32_t insize, uint8_t *output) { sha256(input, insize, output); } - static int32_t check_object_valid(struct storage_object *object) { + /* uboot does not support hash checking */ +#if 0 uint8_t temp[32]; storage_hash(object->dataptr, object->datasize, temp); @@ -39,105 +45,84 @@ static int32_t check_object_valid(struct storage_object *object) return 0; else return -1; +#endif + return 0; } int32_t storage_writeToFlash(void) { - uint8_t *internal_storage = NULL; - uint8_t *penchead, *pcontent, *pcontent_bak; - uint8_t *pns_rawhead, *pns_enchead, *pns_content; - struct storage_block_raw_head *rawhead_t; - struct storage_block_enc_head enchead_t; - struct storage_node *node; - struct storage_object *obj; + uint8_t *pblock = + (uint8_t *)get_share_storage_block_base(); + struct emmc_key_head *pemmc_key_head; + struct key_storage_head *pstorage_key_head; + uint8_t *pkey_data; + struct storage_node *node; + struct storage_object *obj; + uint32_t pos = 0; - uint32_t datasize; - uint32_t outlen; - uint32_t sumsize; - int32_t ret = 0; - - - internal_storage = (uint8_t *)get_internal_storage_base(); - if (!internal_storage) - goto storage_writeflash_err; - - penchead = internal_storage + STORAGE_BLOCK_RAW_HEAD_SIZE; - pcontent = penchead + STORAGE_BLOCK_ENC_HEAD_SIZE; - pcontent_bak = pcontent; - pns_rawhead = (uint8_t *)get_share_storage_block_base(); - pns_enchead = pns_rawhead + STORAGE_BLOCK_RAW_HEAD_SIZE; - pns_content = pns_enchead + STORAGE_BLOCK_ENC_HEAD_SIZE; - - /* internal: raw head */ - memset(pns_rawhead, 0, STORAGE_BLOCK_RAW_HEAD_SIZE); - rawhead_t = (struct storage_block_raw_head *)pns_rawhead; - memcpy(rawhead_t->mark, "AMLSECURITY", 11); - rawhead_t->version = BLOCK_VERSION; - rawhead_t->enctype = storage_chose_enctype(); - /*fixme: no enc support now*/ - //set_encryptkeyfrom(rawhead_t->enctype); - - /* internal: storage */ - datasize = 0; - list_for_each_entry(node, &nodelist, list) - if (datasize < STORAGE_BLOCK_SIZE - - STORAGE_BLOCK_RAW_HEAD_SIZE - - STORAGE_BLOCK_ENC_HEAD_SIZE) { - obj = &(node->object); - if ((node->status & OBJ_STATUS_VALID) - && (obj->dataptr)) { - Tlv_WriteObject(obj, pcontent, &outlen); - datasize += outlen; - pcontent += outlen; - } - } - sumsize = (((datasize+15)/16)*16); - sumsize += STORAGE_BLOCK_RAW_HEAD_SIZE; - sumsize += STORAGE_BLOCK_ENC_HEAD_SIZE; - if (sumsize > flash_storage_size) { - //ERROR("storage size is larger than flash!\n"); - goto storage_writeflash_err; + /* for emmc , there is an extra header to be handled */ + /* the below check is ugly, someone should move the + * related code to emmc key + */ + if (kallsyms_lookup_name("emmc_key_read")) { + pemmc_key_head = (struct emmc_key_head *)pblock; + pstorage_key_head = (struct key_storage_head *) + (pblock + sizeof(struct emmc_key_head)); + } else { + pemmc_key_head = NULL; + pstorage_key_head = (struct key_storage_head *)pblock; } - memset(&enchead_t, 0, sizeof(enchead_t)); - enchead_t.blocksize = datasize; - enchead_t.flashsize = flash_storage_size; - Tlv_WriteHead(&enchead_t, penchead); -#if 1 - ret = do_aes_internal(1, penchead, - STORAGE_BLOCK_ENC_HEAD_SIZE, - pns_enchead, (int *)&outlen); - if (ret) - goto storage_writeflash_err; -#else - ret = 0; - memcpy(pns_enchead, penchead, - STORAGE_BLOCK_ENC_HEAD_SIZE); -#endif -#if 1 - ret = do_aes_internal(1, pcontent_bak, - ((datasize+15)/16)*16, - pns_content, (int *)&outlen); - if (ret) - goto storage_writeflash_err; -#else - ret = 0; - memcpy(pns_content, pcontent_bak, ((datasize+15)/16)*16); -#endif - /* write message*/ - //msg->cmd = MSG_CMD_WRITEKEY; - //msg->state += 1; - ret = 0; - version = BLOCK_VERSION; - aesfrom = storage_chose_enctype(); - goto storage_writeflash_exit; + /* fill storage key header */ + memset(pstorage_key_head, 0x00, sizeof(struct key_storage_head)); + memcpy(pstorage_key_head->mark, "keyexist", 8); + pstorage_key_head->version = 2; + pstorage_key_head->item_cnt = 0; + pstorage_key_head->size = 0; -storage_writeflash_err: - ret = -1; -storage_writeflash_exit: - return ret; + pstorage_key_head->size += sizeof(struct key_storage_head); + pkey_data = (uint8_t *)pstorage_key_head + + sizeof(struct key_storage_head); + + //list_for_each_entry(node, &nodelist, list) + list_for_each_entry_reverse(node, &nodelist, list) + if (node->status & OBJ_STATUS_VALID) { + obj = &(node->object); + pstorage_key_head->item[pstorage_key_head-> + item_cnt].position = pos; + memcpy(&pkey_data[pos], + obj, sizeof(struct storage_object)); + pos += sizeof(struct storage_object); + memcpy(&pkey_data[pos], + obj->storage_data, obj->storage_size); + pos += obj->storage_size; + + + pstorage_key_head->size += + sizeof(struct storage_object); + pstorage_key_head->size += obj->storage_size; + pstorage_key_head->item_cnt++; + } + + if (pemmc_key_head != NULL) { + /* fill the extra emmc key header */ + memset(pemmc_key_head, 0x00, sizeof(struct emmc_key_head)); + memcpy(pemmc_key_head->mark, "emmckeys", 8); + emmc_key_transfer(pemmc_key_head->mark, + &pemmc_key_head->mark_checksum, 8, 1); + /* + * do not blame me for the magic number 128*1024-28, + * only to be compatible for old next-dev + */ + pemmc_key_head->checksum = + emmckey_checksum((uint8_t *)pstorage_key_head, + 128*1024-28); + } + + return RET_OK; } + static void __storage_add(struct storage_node *node) { list_add(&node->list, &nodelist); @@ -148,6 +133,8 @@ static void __storage_del(struct storage_node *node) list_del(&node->list); if (node->object.dataptr != NULL) storage_free(node->object.dataptr); + if (node->object.storage_data != NULL) + storage_free(node->object.storage_data); storage_free(node); } @@ -173,7 +160,7 @@ static struct storage_node *storage_create_empty(void) { struct storage_node *node; - node = storage_malloc(sizeof(*node)); + node = storage_zalloc(sizeof(*node)); if (node == NULL) return NULL; memset(node, 0, sizeof(struct storage_node)); @@ -182,6 +169,7 @@ static struct storage_node *storage_create_empty(void) return node; } + static struct storage_node *storage_create(uint8_t *name, uint32_t namelen) { struct storage_node *node; @@ -198,6 +186,12 @@ static struct storage_node *storage_create(uint8_t *name, uint32_t namelen) return node; } +static void storage_del(struct storage_node *node) +{ + __storage_del(node); +} + + static void storage_reset(void) { struct storage_node *node; @@ -206,6 +200,7 @@ static void storage_reset(void) __storage_del(node); } + static int32_t storage_infocheck(struct storage_node *node, uint32_t attr) { struct storage_object *obj = &(node->object); @@ -216,54 +211,177 @@ static int32_t storage_infocheck(struct storage_node *node, uint32_t attr) return -1; } + +static uint16_t aml_key_checksum(char *data, int length) +{ + uint16_t checksum; + uint8_t *pdata; + int i; + + checksum = 0; + pdata = (uint8_t *)data; + for (i = 0; i < length; i++) + checksum += pdata[i]; + + return checksum; +} + + +static uint32_t emmckey_checksum(uint8_t *buf, uint32_t length) +{ + uint32_t checksum = 0; + uint32_t cnt; + + for (cnt = 0; cnt < length; cnt++) + checksum += buf[cnt]; + + return checksum; +} + + + +static int is_hex_str(uint8_t *buf, uint32_t len) +{ + uint32_t i; + + for (i = 0; i < len; i++) + switch (buf[i]) { + case '0' ... '9': + case 'a' ... 'f': + case 'A' ... 'F': + break; + default: + return 0; + } + return 1; +} + +static char asc_to_hex(char para) +{ + if (para >= '0' && para <= '9') + para = para-'0'; + else if (para >= 'a' && para <= 'f') + para = para - 'a'+0xa; + else if (para >= 'A' && para <= 'F') + para = para-'A'+0xa; + + return para; +} + + +uint32_t to_storage_data(uint8_t *data, uint32_t valid_size, + uint8_t *storage_data, uint16_t storage_size, + uint16_t *checksum) +{ + uint8_t *tmp_buf; + uint8_t *data_clone; + uint8_t chr; + int i; + uint32_t valid_comp_size = 0; + int enc_data_len = 0; + + + if (!is_hex_str(data, valid_size)) + return RET_EINVAL; + + data_clone = storage_zalloc(valid_size); + if (!data_clone) + return RET_EMEM; + memcpy(data_clone, data, valid_size); + + for (i = 0; i < valid_size; i++) { + chr = data_clone[i]; + if (i%2 == 0) + data_clone[i/2] = 0x00; + data_clone[i/2] |= (i%2 == 0) ? + (asc_to_hex(chr) << 4):(asc_to_hex(chr) & 0xf); + } + + + valid_comp_size = (valid_size+1)>>1; + *checksum = aml_key_checksum(data_clone, valid_comp_size); + + tmp_buf = storage_zalloc(storage_size); + if (!tmp_buf) { + storage_free(data_clone); + return RET_EMEM; + } + memcpy(tmp_buf, &valid_comp_size, 4); + memcpy(tmp_buf+4, data_clone, valid_comp_size); + + do_aes_internal(1, tmp_buf, storage_size, storage_data, &enc_data_len); + + storage_free(tmp_buf); + storage_free(data_clone); + + return RET_OK; +} + + uint32_t storage_write(uint8_t *name, uint32_t namelen, uint8_t *writebuf, uint32_t bufsize, uint32_t attr) { - struct storage_node *node; + struct storage_node *node; struct storage_object *object; + int is_new = 0; - if (namelen >= MAX_OBJ_NAME_LEN) + + if ((namelen >= MAX_OBJ_NAME_LEN) || + !is_hex_str(writebuf, bufsize)) return RET_EINVAL; + + /* update key node */ node = storage_find(name, namelen); if (node == NULL) { /*it's new object*/ + is_new = 1; node = storage_create(name, namelen); if (node == NULL) return RET_EMEM; object = &(node->object); - object->dataptr = storage_malloc((int32_t)bufsize); - if (!object->dataptr) - return RET_EMEM; node->status |= OBJ_STATUS_VALID; object->attribute = attr; + object->namesize = namelen; object->type = OBJ_TYPE_GENERIC; - memcpy(object->dataptr, writebuf, bufsize); - object->datasize = bufsize; - storage_hash(object->dataptr, - object->datasize, object->hashptr); + object->type1 = 0x41c; /* be compatible with old unifykey */ } else { /* the object is existed*/ + /* TODO: check whether attr is updated correctly */ if (storage_infocheck(node, attr) < 0) return RET_EINVAL; object = &(node->object); - if (object->datasize < bufsize) { - storage_free(object->dataptr); - object->dataptr = storage_malloc(bufsize); - if (!object->dataptr) - return RET_EMEM; - memcpy(object->dataptr, writebuf, bufsize); - object->datasize = bufsize; - storage_hash(object->dataptr, - object->datasize, object->hashptr); - } else { - memcpy(object->dataptr, writebuf, bufsize); - object->datasize = bufsize; - storage_hash(object->dataptr, - object->datasize, object->hashptr); - } + storage_free(object->dataptr); + storage_free(object->storage_data); } - if (!storage_writeToFlash()) - return RET_OK; - else + object->datasize = bufsize; + object->valid_size = bufsize; + object->storage_size = (((((object->valid_size+1)>>1)+4)+15)>>4)<<4; + object->dataptr = storage_zalloc(object->valid_size); + if (!object->dataptr) { + if (is_new) + storage_del(node); + return RET_EMEM; + } + object->storage_data = storage_zalloc(object->storage_size); + if (!object->storage_data) { + if (is_new) + storage_del(node); + return RET_EMEM; + } + memcpy(object->dataptr, writebuf, object->valid_size); + + if (to_storage_data(object->dataptr, object->valid_size, + object->storage_data, object->storage_size, + &object->checksum) != RET_OK) { + if (is_new) + storage_del(node); return RET_EFAIL; + } + + storage_hash(object->dataptr, + object->datasize, object->hashptr); + + storage_writeToFlash(); + + return RET_OK; } static int32_t storage_read_permit(struct storage_node *node) @@ -385,101 +503,151 @@ uint32_t storage_status(uint8_t *name, uint32_t namelen, uint32_t *retval) return RET_OK; } +static int emmc_key_transfer(u8 *buf, u32 *value, u32 len, u32 direct) +{ + u8 checksum = 0; + u32 i; + + if (direct) { + for (i = 0; i < len; i++) + checksum += buf[i]; + for (i = 0; i < len; i++) + buf[i] ^= checksum; + *value = checksum; + } else { + checksum = *value; + for (i = 0; i < len; i++) + buf[i] ^= checksum; + checksum = 0; + for (i = 0; i < len; i++) + checksum += buf[i]; + if (checksum == *value) + return 0; + return -1; + } + + return 0; +} + + /* initialize nodelist from internal storage block*/ void storage_init(uint32_t flashsize) { - uint8_t *internal_storage; - struct storage_block_raw_head *prawhead; - struct storage_block_enc_head enchead; - uint8_t *pcontent, *prawcontent; - uint8_t *pblock = (uint8_t *)get_share_storage_block_base(); + uint8_t *pblock = + (uint8_t *)get_share_storage_block_base(); + struct emmc_key_head *pemmc_key_head; + struct key_storage_head *pstorage_key_head; + int key_count; + int i, j, n; + struct storage_node *node; + struct storage_object *tmp_obj; + char *tmp_content; + uint8_t *tmp; + int out_len; + int key_hex_len; - int32_t ret; - uint32_t outlen, sum; - struct storage_node *node; + /* we should handle an extra header for emmc key */ + if (kallsyms_lookup_name("emmc_key_read")) { + pemmc_key_head = (struct emmc_key_head *)pblock; + pstorage_key_head = (struct key_storage_head *) + (pblock + sizeof(struct emmc_key_head)); + } else { + pemmc_key_head = NULL; + pstorage_key_head = (struct key_storage_head *)pblock; + } + if (pemmc_key_head != NULL) { + if (!emmc_key_transfer(pemmc_key_head->mark, + &pemmc_key_head->mark_checksum, 8, 0)) { + if (memcmp(pemmc_key_head->mark, + "emmckeys", 8) != 0) { + flash_storage_size = flashsize; + goto storage_init_err; + } + } else { + flash_storage_size = flashsize; + goto storage_init_err; + } + } - /* reset */ - storage_reset(); - internal_storage = (uint8_t *)get_internal_storage_base(); - if (!internal_storage) - goto storage_init_err; - - aesfrom = -1; - version = -1; - prawhead = (struct storage_block_raw_head *)pblock; - if (strcmp((const char *)(prawhead->mark), "AMLSECURITY") != 0) { + if (memcmp(pstorage_key_head->mark, "keyexist", 8) != 0) { flash_storage_size = flashsize; goto storage_init_err; } - aesfrom = prawhead->enctype; - /*fixme: no enc support now*/ -#if 0 - set_encryptkeyfrom(aesfrom); -#endif - version = prawhead->version; -#if 1 - ret = do_aes_internal(0, - pblock+STORAGE_BLOCK_RAW_HEAD_SIZE, - STORAGE_BLOCK_ENC_HEAD_SIZE, - internal_storage, (int *)&outlen); - if (ret) { - flash_storage_size = flashsize; - goto storage_init_err; - } -#else - memcpy(internal_storage, pblock + STORAGE_BLOCK_RAW_HEAD_SIZE, - STORAGE_BLOCK_ENC_HEAD_SIZE); -#endif - - memset(&enchead, 0, sizeof(enchead)); - ret = Tlv_ReadHead(internal_storage, &enchead); - if (ret || (enchead.blocksize == 0)) { - flash_storage_size = flashsize; - goto storage_init_err; - } - if (enchead.flashsize != 0) - flash_storage_size = enchead.flashsize; - if (flash_storage_size != flashsize) - goto storage_init_err; - - pcontent = pblock+STORAGE_BLOCK_RAW_HEAD_SIZE - + STORAGE_BLOCK_ENC_HEAD_SIZE; - prawcontent = internal_storage + STORAGE_BLOCK_ENC_HEAD_SIZE; -#if 1 - ret = do_aes_internal(0, pcontent, ((enchead.blocksize+15)/16)*16, - prawcontent, (int *)&outlen); - if (ret) - goto storage_init_err; -#else - memcpy(prawcontent, pcontent, ((enchead.blocksize+15)/16)*16); -#endif - sum = enchead.blocksize; - while (sum > 0) { + /* parse each key */ + tmp_content = (char *)&pstorage_key_head[1]; // skip storage key header + key_count = pstorage_key_head->item_cnt; + for (i = 0; i < key_count; i++) { node = storage_create_empty(); if (node == NULL) goto storage_init_err; - ret = Tlv_ReadObject(prawcontent, node, &outlen); - if (ret) + + tmp_obj = (struct storage_object *) + &tmp_content[pstorage_key_head->item[i].position]; + node->object.slot = tmp_obj->slot; + node->object.state = tmp_obj->state; + node->object.storage_size = tmp_obj->storage_size; + node->object.valid_size = tmp_obj->valid_size; + node->object.type1 = tmp_obj->type1; + node->object.checksum = tmp_obj->checksum; + node->object.type = tmp_obj->type; + node->object.attribute = tmp_obj->attribute; + node->object.datasize = tmp_obj->valid_size; + strcpy(node->object.name, tmp_obj->name); + node->object.namesize = strlen(node->object.name); + + node->object.storage_data = + storage_malloc(node->object.storage_size); + if (node->object.storage_data == NULL) goto storage_init_err; - ret = check_object_valid(&(node->object)); - if (!ret) + node->object.dataptr = storage_malloc(node->object.valid_size); + if (node->object.dataptr == NULL) + goto storage_init_err; + memcpy(node->object.storage_data, + &tmp_content[pstorage_key_head->item[i].position+ + sizeof(struct storage_object)], + node->object.storage_size); + memcpy(node->object.hashptr, tmp_obj->hashptr, + sizeof(tmp_obj->hashptr)); + + /* decrypt each key */ + tmp = storage_malloc(node->object.storage_size); + if (tmp == NULL) + goto storage_init_err; + + do_aes_internal(0, node->object.storage_data, + node->object.storage_size, tmp, &out_len); + memcpy(&key_hex_len, tmp, 4); + tmp = tmp + 4; + + /* switch to ascii form */ + /* TODO: add checksum validation(refer to key_core_show) */ + memset(node->object.dataptr, 0x00, node->object.valid_size); + n = 0; + for (j = 0; j < node->object.valid_size>>1; j++) + n += sprintf(&node->object.dataptr[n], "%02x", tmp[j]); + if (node->object.valid_size % 2) + n += sprintf(&node->object.dataptr[n], "%x", + (tmp[j]&0xf0)>>4); + tmp = tmp - 4; + storage_free(tmp); + + if (check_object_valid(&(node->object)) == 0) node->status = OBJ_STATUS_VALID; else node->status = OBJ_STATUS_INVALID; - sum -= outlen; - prawcontent += outlen; } + goto storage_init_exit; storage_init_err: - storage_reset(); - free_share_storage(); - free_internal_storage(); + storage_reset(); + free_share_storage(); + free_internal_storage(); storage_init_exit: - return; + return; } uint32_t get_share_storage_block_base(void) diff --git a/drivers/amlogic/unifykey/v7/key_storage/storage.h b/drivers/amlogic/unifykey/v7/key_storage/storage.h index 33a1d109fb01..6f802c95b376 100644 --- a/drivers/amlogic/unifykey/v7/key_storage/storage.h +++ b/drivers/amlogic/unifykey/v7/key_storage/storage.h @@ -22,7 +22,11 @@ #include #include -#define MAX_OBJ_NAME_LEN 80 +#define KEY_MAX_COUNT 32 + + +#define MAX_OBJ_NAME_LEN 16 +#define MAX_MAGIC_STR_LEN 16 /*Attribute*/ #define OBJ_ATTR_SECURE (1<<0) @@ -33,13 +37,21 @@ #define OBJ_TYPE_GENERIC 0xA00000BF struct storage_object { - char name[MAX_OBJ_NAME_LEN]; + char name[MAX_OBJ_NAME_LEN]; + uint16_t slot; + uint16_t type1; + uint16_t valid_size; + uint16_t storage_size; + uint16_t state; + uint16_t checksum; + char hashptr[36]; uint32_t namesize; uint32_t attribute; /*secure, OTP*/ uint32_t type; /*AES, RSA, GENERIC, ...*/ uint32_t datasize; - uint8_t *dataptr; - uint8_t hashptr[32]; + char reserve[40]; + uint8_t *storage_data; + uint8_t *dataptr; }; #define OBJ_STATUS_FREE 0 @@ -57,6 +69,31 @@ struct storage_node { #define ENC_TYPE_FIXED 2 #define STORAGE_BLOCK_RAW_HEAD_SIZE 512 #define BLOCK_VERSION 0 + +struct emmc_key_head { + uint8_t mark[MAX_MAGIC_STR_LEN]; + uint32_t mark_checksum; + uint32_t checksum; + uint32_t reserve; +}; + +struct key_head_item { + uint32_t position; + uint32_t state; + uint32_t reserve; +}; +struct key_storage_head { + char mark[MAX_MAGIC_STR_LEN]; + uint32_t version; + uint32_t inver; //inver = ~version + 1 + uint32_t tag; + uint32_t size; //tatol size + uint32_t item_cnt; + struct key_head_item item[KEY_MAX_COUNT]; + char reserve[92]; +}; + + struct storage_block_raw_head { uint8_t mark[16]; /* AMLSECURITY*/ uint32_t version; diff --git a/drivers/amlogic/unifykey/v7/key_storage/storage_data.h b/drivers/amlogic/unifykey/v7/key_storage/storage_data.h index 4fda93496d4c..2a428759f80f 100644 --- a/drivers/amlogic/unifykey/v7/key_storage/storage_data.h +++ b/drivers/amlogic/unifykey/v7/key_storage/storage_data.h @@ -25,7 +25,7 @@ static LIST_HEAD(nodelist); static int32_t aesfrom = -1; static int32_t aesfrom_outer = -1; -static int32_t version; +//static int32_t version; static uint8_t *storage_shar_in_block; static uint8_t *storage_shar_out_block; static uint8_t *storage_share_block; diff --git a/drivers/amlogic/unifykey/v7/key_storage/storage_util.c b/drivers/amlogic/unifykey/v7/key_storage/storage_util.c index 658628895957..d82fe967b268 100644 --- a/drivers/amlogic/unifykey/v7/key_storage/storage_util.c +++ b/drivers/amlogic/unifykey/v7/key_storage/storage_util.c @@ -25,7 +25,13 @@ void *storage_malloc(int32_t size) return kmalloc(size, GFP_KERNEL); } +void *storage_zalloc(int32_t size) +{ + return kzalloc(size, GFP_KERNEL); +} + void storage_free(void *ptr) { - kfree(ptr); + if (ptr != NULL) + kfree(ptr); } diff --git a/drivers/amlogic/unifykey/v7/key_storage/storage_util.h b/drivers/amlogic/unifykey/v7/key_storage/storage_util.h index 9f46b023d31b..db6a28a16853 100644 --- a/drivers/amlogic/unifykey/v7/key_storage/storage_util.h +++ b/drivers/amlogic/unifykey/v7/key_storage/storage_util.h @@ -21,6 +21,7 @@ #include void *storage_malloc(int32_t size); +void *storage_zalloc(int32_t size); void storage_free(void *ptr); #endif diff --git a/drivers/amlogic/unifykey/v7/key_storage/tlv.c b/drivers/amlogic/unifykey/v7/key_storage/tlv.c deleted file mode 100644 index eee036d5dc18..000000000000 --- a/drivers/amlogic/unifykey/v7/key_storage/tlv.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * drivers/amlogic/unifykey/v7/key_storage/tlv.c - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#include -#include "storage.h" -#include "storage_util.h" - -static uint32_t Tlv_WriteUint32(uint8_t *output, uint32_t tag, uint32_t value) -{ - uint8_t *out; - - out = output; - *((uint32_t *)out) = tag; - out += 4; - *((uint32_t *)out) = 4; - out += 4; - *((uint32_t *)out) = value; - return 12; -} - -static uint32_t Tlv_WriteBuf(uint8_t *output, uint32_t tag, - uint32_t length, uint8_t *input) -{ - uint8_t *out = output; - *((uint32_t *)out) = tag; - out += 4; - *((uint32_t *)out) = (((length+3)/4)*4); - out += 4; - memset(out, 0, ((length+3)/4)*4); - memcpy(out, input, length); - return 8+(((length+3)/4)*4); -} - -int32_t Tlv_ReadHead(uint8_t *buf, struct storage_block_enc_head *pblockhead) -{ - uint32_t tag; - uint32_t sum; - uint32_t length; - uint8_t *input; - - input = buf; - tag = *((uint32_t *)input); - input += 4; - sum = *((uint32_t *)input); - input += 4; - if (tag != emTlvHead) - return -1; - - while (sum > 0) { - tag = *((unsigned int *)input); - input += 4; - length = *((unsigned int *)input); - input += 4; - sum -= 8; - switch (tag) { - case emTlvHeadSize: - pblockhead->blocksize = *((uint32_t *)input); - sum -= length; - input += length; - break; - case emTlvHeadFlashSize: - pblockhead->flashsize = *((uint32_t *)input); - sum -= length; - input += length; - break; - default: - sum -= length; - input += length; - break; - } - } - return 0; -} - -int32_t Tlv_ReadObject(uint8_t *input, - struct storage_node *node, uint32_t *allsize) -{ - uint8_t *buf; - uint32_t tag; - uint32_t length; - uint32_t isum; - struct storage_object *pcontent = &(node->object); - - buf = input; - tag = *(unsigned int *)buf; - buf += 4; - isum = *(unsigned int *)buf; - buf += 4; - if (tag != emTlvObject) - return -1; - *allsize = isum+8; - - while (isum > 0) { - tag = *(uint32_t *)buf; - buf += 4; - length = *(uint32_t *)buf; - buf += 4; - isum -= 8; - switch (tag) { - case emTlvObjNameSize: - pcontent->namesize = *((uint32_t *)buf); - buf += 4; - isum -= 4; - break; - case emTlvObjName: - memset(pcontent->name, 0, MAX_OBJ_NAME_LEN); - memcpy(pcontent->name, buf, pcontent->namesize); - buf += length; - isum -= length; - break; - case emTlvObjType: - pcontent->type = *((uint32_t *)buf); - buf += 4; - isum -= 4; - break; - case emTlvObjAttr: - pcontent->attribute = *((uint32_t *)buf); - buf += 4; - isum -= 4; - break; - case emTlvObjDataSize: - pcontent->datasize = *((uint32_t *)buf); - buf += 4; - isum -= 4; - break; - case emTlvObjHashBuf: - if (length != 32) - goto Tlv_ReadKeyContent_err; - memcpy(pcontent->hashptr, buf, length); - buf += length; - isum -= length; - break; - case emTlvObjDataBuf: - pcontent->dataptr = - storage_malloc(pcontent->datasize); - if (!pcontent->dataptr) - goto Tlv_ReadKeyContent_err; - memcpy(pcontent->dataptr, - buf, pcontent->datasize); - buf += length; - isum -= length; - break; - default: - buf += length; - isum -= length; - break; - } - } - return 0; - -Tlv_ReadKeyContent_err: - node->status = OBJ_STATUS_INVALID; - return -1; -} - -void Tlv_WriteHead(struct storage_block_enc_head *enchead, uint8_t *output) -{ - uint8_t *buffer; - uint32_t *sum; - uint32_t length; - - buffer = output; - *(uint32_t *)buffer = emTlvHead; - buffer += 4; - sum = (uint32_t *)buffer; - buffer += 4; - - *sum = 0; - - length = Tlv_WriteUint32(buffer, emTlvHeadSize, enchead->blocksize); - *sum += length; - buffer += length; - - length = Tlv_WriteUint32(buffer, emTlvHeadFlashSize, - enchead->flashsize); - *sum += length; - buffer += length; -} - -void Tlv_WriteObject(struct storage_object *object, - uint8_t *output, uint32_t *outlen) -{ - uint32_t length; - uint32_t *sum; - uint8_t *buffer; - uint32_t temp; - - buffer = output; - *outlen = 0; - *(uint32_t *)buffer = emTlvObject; - buffer += 4; - sum = (uint32_t *)buffer; - buffer += 4; - *outlen += 8; - - temp = strlen(object->name); - if (temp != 0) { - length = Tlv_WriteUint32(buffer, emTlvObjNameSize, temp); - buffer += length; - *outlen += length; - - length = Tlv_WriteBuf(buffer, emTlvObjName, - temp, (uint8_t *)(object->name)); - buffer += length; - *outlen += length; - } - - if (object->dataptr && (object->datasize != 0)) { - length = Tlv_WriteUint32(buffer, - emTlvObjDataSize, object->datasize); - buffer += length; - *outlen += length; - - length = Tlv_WriteBuf(buffer, emTlvObjDataBuf, - object->datasize, object->dataptr); - buffer += length; - *outlen += length; - } - - length = Tlv_WriteBuf(buffer, emTlvObjHashBuf, 32, object->hashptr); - buffer += length; - *outlen += length; - - length = Tlv_WriteUint32(buffer, emTlvObjType, object->type); - buffer += length; - *outlen += length; - - length = Tlv_WriteUint32(buffer, emTlvObjAttr, object->attribute); - buffer += length; - *outlen += length; - - *sum = (*outlen-8); -}