| /* |
| * 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. |
| * * |
| You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| * * |
| Description: |
| */ |
| |
| |
| #include "ini_config.h" |
| |
| #define LOG_TAG "UnifyKey" |
| #define LOG_NDEBUG 0 |
| |
| #include "ini_log.h" |
| |
| #include "UnifyKey.h" |
| |
| #define CC_ONE_SECTION_SIZE (0x1000) |
| |
| #if (defined (CC_INI_IO_USE_UNIFY_KEY)) |
| |
| #if (!defined (CC_INI_IO_UKEY_USE_OTHER_MODULE)) |
| |
| #if (defined(CC_COMPILE_IN_PC) || defined(CC_COMPILE_IN_ANDROID)) |
| |
| #if (defined CC_COMPILE_IN_PC) |
| |
| #define CS_KEY_DATA_LIST_DEV_PATH "sys/class/unifykeys/list" |
| #define CS_KEY_DATA_NAME_DEV_PATH "sys/class/unifykeys/name" |
| |
| static char gDevPath[256] = {0}; |
| static int GetDevPath(char path_buf[]) { |
| int tmp_len = 0; |
| FILE *dev_fp = NULL; |
| |
| strcpy(path_buf, "sys/class/unifykeys/"); |
| dev_fp = fopen(CS_KEY_DATA_NAME_DEV_PATH, "r"); |
| if (dev_fp == NULL) { |
| ALOGE("%s, open %s ERROR(%s)!!\n", __FUNCTION__, |
| CS_KEY_DATA_NAME_DEV_PATH, strerror(errno)); |
| return -1; |
| } |
| |
| tmp_len = strlen(path_buf); |
| fscanf(dev_fp, "%s", path_buf + tmp_len); |
| |
| fclose(dev_fp); |
| dev_fp = NULL; |
| |
| return 0; |
| } |
| |
| static const char *GetKeyDataWriteDevPath() { |
| memset((void *)gDevPath, 0, 256); |
| GetDevPath(gDevPath); |
| return gDevPath; |
| } |
| |
| static const char *GetKeyDataReadDevPath() { |
| memset((void *)gDevPath, 0, 256); |
| GetDevPath(gDevPath); |
| return gDevPath; |
| } |
| |
| #else |
| |
| #define CS_KEY_DATA_LIST_DEV_PATH "/sys/class/unifykeys/list" |
| #define CS_KEY_DATA_NAME_DEV_PATH "/sys/class/unifykeys/name" |
| |
| static const char *GetKeyDataWriteDevPath() { |
| return "/sys/class/unifykeys/write"; |
| } |
| |
| static const char *GetKeyDataReadDevPath() { |
| return "/sys/class/unifykeys/read"; |
| } |
| |
| #endif //CC_COMPILE_IN_PC |
| |
| static int checkKeyNameInList(const char *key_name) { |
| FILE *dev_fp = NULL; |
| char *tmp_ptr = NULL; |
| char lineStr[1024]; |
| |
| dev_fp = fopen(CS_KEY_DATA_LIST_DEV_PATH, "r"); |
| if (dev_fp == NULL) { |
| ALOGE("%s, open %s ERROR(%s)!!\n", __FUNCTION__, |
| CS_KEY_DATA_LIST_DEV_PATH, strerror(errno)); |
| return -1; |
| } |
| |
| while (fgets(lineStr, 1024, dev_fp) != NULL) { |
| tmp_ptr = strstr(lineStr, key_name); |
| if (tmp_ptr != NULL) { |
| break; |
| } |
| |
| tmp_ptr = NULL; |
| } |
| |
| fclose(dev_fp); |
| dev_fp = NULL; |
| |
| if (tmp_ptr == NULL) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| int readUKeyData(const char *key_name, unsigned char data_buf[], int rd_size) { |
| int rd_cnt = 0; |
| FILE *dev_fp = NULL; |
| |
| if (checkKeyNameInList(key_name) < 0) { |
| ALOGE("%s, key \"%s\" isn't exist in unifykeys list\n", __FUNCTION__, key_name); |
| return -1; |
| } |
| |
| dev_fp = fopen(CS_KEY_DATA_NAME_DEV_PATH, "w"); |
| if (dev_fp == NULL) { |
| ALOGE("%s, open %s ERROR(%s)!!\n", __FUNCTION__, |
| CS_KEY_DATA_NAME_DEV_PATH, strerror(errno)); |
| return -1; |
| } |
| |
| fprintf(dev_fp, "%s", key_name); |
| |
| fclose(dev_fp); |
| dev_fp = NULL; |
| |
| int mode = 1; |
| |
| if (mode == 0) { |
| dev_fp = fopen(GetKeyDataReadDevPath(), "r"); |
| if (dev_fp == NULL) { |
| ALOGE("%s, open %s ERROR(%s)!!\n", __FUNCTION__, |
| GetKeyDataReadDevPath(), strerror(errno)); |
| return -1; |
| } |
| |
| fscanf(dev_fp, "%s", data_buf); |
| rd_cnt = strlen((char *) data_buf); |
| } else { |
| dev_fp = fopen(GetKeyDataReadDevPath(), "rb"); |
| if (dev_fp == NULL) { |
| ALOGE("%s, open %s ERROR(%s)!!\n", __FUNCTION__, |
| GetKeyDataReadDevPath(), strerror(errno)); |
| return -1; |
| } |
| |
| rd_cnt = fread(data_buf, 1, CC_ONE_SECTION_SIZE, dev_fp); |
| } |
| |
| fclose(dev_fp); |
| dev_fp = NULL; |
| |
| return rd_cnt; |
| } |
| |
| int writeUKeyData(const char *key_name, unsigned char data_buf[], int wr_size) { |
| int wr_cnt = 0; |
| int dev_fd = -1; |
| FILE *dev_fp = NULL; |
| |
| if (checkKeyNameInList(key_name) < 0) { |
| ALOGE("%s, key \"%s\" isn't exist in unifykeys list\n", __FUNCTION__, key_name); |
| return -1; |
| } |
| |
| dev_fp = fopen(CS_KEY_DATA_NAME_DEV_PATH, "w"); |
| if (dev_fp == NULL) { |
| ALOGE("%s, open %s ERROR(%s)!!\n", __FUNCTION__, |
| CS_KEY_DATA_NAME_DEV_PATH, strerror(errno)); |
| return -1; |
| } |
| |
| fprintf(dev_fp, "%s", key_name); |
| |
| fclose(dev_fp); |
| dev_fp = NULL; |
| |
| dev_fd = open(GetKeyDataWriteDevPath(), O_WRONLY | O_SYNC | O_CREAT | O_TRUNC, S_IRWXU | S_IRWXG | S_IRWXO); |
| |
| if (dev_fd < 0) { |
| ALOGE("%s, open %s ERROR(%s)!!\n", __FUNCTION__, |
| GetKeyDataWriteDevPath(), strerror(errno)); |
| return -1; |
| } |
| |
| wr_cnt = write(dev_fd, data_buf, wr_size); |
| |
| fsync(dev_fd); |
| |
| close(dev_fd); |
| dev_fd = -1; |
| |
| return wr_cnt; |
| } |
| |
| #elif (defined CC_COMPILE_IN_UBOOT) |
| |
| #include "model.h" |
| |
| #define CC_UKEY_RETRY_CNT_MAX (5) |
| |
| static int checkUnifyKey(const char *key_name) { |
| int ret = 0, key_exist = 0, isSecure = 0; |
| unsigned int key_len = 0; |
| ssize_t key_size = 0; |
| |
| // start check the key is exist? |
| ret = key_unify_query_exist(key_name, &key_exist); |
| if (ret) { |
| ALOGE("%s, %s query exist error.\n",__FUNCTION__, key_name); |
| return -1; |
| } |
| if (key_exist == 0) { |
| ALOGE("%s, %s is not exist.\n",__FUNCTION__, key_name); |
| return -1; |
| } |
| // end check the key is exist? |
| |
| // start check the key is secure? |
| ret = key_unify_query_secure(key_name, &isSecure); |
| if (ret) { |
| ALOGE("%s, %s query secure error\n",__FUNCTION__, key_name); |
| return -1; |
| } |
| if (isSecure) { |
| ALOGE("%s, %s is secure key\n",__FUNCTION__, key_name); |
| return -1; |
| } |
| // end check the key is secure? |
| |
| // start read and check data integrity |
| ret = key_unify_query_size(key_name, &key_size); |
| if (ret) { |
| ALOGE("%s, %s query size error\n",__FUNCTION__, key_name); |
| return -1; |
| } |
| //ALOGD("%s, %s size: %d\n",__FUNCTION__, key_name, (int)key_size); |
| |
| key_len = (int)key_size; |
| //ALOGD("%s, %s size: %d\n",__FUNCTION__, key_name, key_len); |
| |
| return key_len; |
| } |
| |
| int readUKeyData(const char *key_name, unsigned char data_buf[], int rd_size) { |
| int i = 0, ret = 0, key_len = 0, retry_cnt = 0, tmp_content_type = 0; |
| unsigned int key_crc = 0, key_crc32 = 0, tmp_len = 0, tmp_crc = 0; |
| struct all_info_header_s *pHeadPtr = NULL; |
| |
| key_len = checkUnifyKey(key_name); |
| if (key_len < 0) { |
| return -1; |
| } else if (key_len == 0) { |
| ALOGE("%s, %s size is zero\n",__FUNCTION__, key_name); |
| return -1; |
| } else if (key_len > rd_size) { |
| ALOGE("%s, %s key len is larger than rd size.\n",__FUNCTION__, key_name); |
| return -1; |
| } |
| |
| unifykey_read: |
| ret = key_unify_read(key_name, data_buf, key_len); |
| if (ret) { |
| ALOGE("%s, %s unify read error\n",__FUNCTION__, key_name); |
| return -1; |
| } |
| |
| //judge unfikey data type, default is binary data |
| tmp_content_type = 0; |
| for (i = 0; i < 14; i++) { |
| if (i < 8 || (i > 9 && i < 13)) { |
| if (!isxdigit(data_buf[i])) { |
| break; |
| } |
| } else if (i == 8 || i == 13) { |
| if (data_buf[i] != ',') { |
| break; |
| } |
| } else if (i == 9) { |
| if (data_buf[i] != 'V' && data_buf[i] != 'v') { |
| break; |
| } |
| } |
| } |
| |
| if (i == 14) { |
| tmp_content_type = 1; |
| } |
| |
| tmp_crc = 0; |
| tmp_len = 0; |
| if (tmp_content_type == 0) { |
| pHeadPtr = (struct all_info_header_s *)(data_buf); |
| tmp_crc = pHeadPtr->crc32; |
| tmp_len = pHeadPtr->data_len; |
| } else { |
| return key_len; |
| } |
| |
| if (key_len != tmp_len) { |
| ALOGE("%s, %s data_len %d is not match key_len %d\n",__FUNCTION__, |
| key_name, tmp_len, key_len); |
| if (retry_cnt < CC_UKEY_RETRY_CNT_MAX) { |
| retry_cnt++; |
| goto unifykey_read; |
| } else { |
| ALOGE("%s, %s load unifykey failed\n",__FUNCTION__, key_name); |
| return -1; |
| } |
| } |
| |
| key_crc = crc32(0, &data_buf[4], (key_len - 4)); //except crc32 |
| key_crc32 = (unsigned int)key_crc; |
| if (key_crc32 != tmp_crc) { |
| ALOGE("%s, %s crc32 0x%08x is not match 0x%08x\n",__FUNCTION__, |
| key_name, tmp_crc, key_crc32); |
| if (retry_cnt < CC_UKEY_RETRY_CNT_MAX) { |
| retry_cnt++; |
| goto unifykey_read; |
| } else { |
| ALOGE("%s, %s load unifykey failed\n",__FUNCTION__, key_name); |
| return -1; |
| } |
| } |
| // end read and check data integrity |
| |
| return key_len; |
| } |
| |
| int writeUKeyData(const char *key_name, unsigned char data_buf[], int wr_size) { |
| // if the key is not burn data, the fucntion will return fail |
| // now we disable the unifykey check function. |
| /* |
| int key_len = 0; |
| |
| key_len = checkUnifyKey(key_name); |
| if (key_len < 0) { |
| return -1; |
| } |
| */ |
| if (key_unify_write(key_name, data_buf, wr_size) == 0) { |
| return wr_size; |
| } |
| return -1; |
| } |
| |
| #endif |
| |
| #endif |
| |
| #if (defined CC_UBOOT_RW_SIMULATE) |
| |
| #include "ini_io.h" |
| |
| unsigned int crc32(unsigned int crc, const unsigned char *ptr, int buf_len) { |
| return CalCRC32(crc, ptr, buf_len); |
| } |
| |
| static unsigned char gTempBuf[0x400000]; |
| |
| int key_unify_write(const char* keyname, const void* keydata, const unsigned datalen) { |
| int tmp_ret = 0; |
| |
| tmp_ret = writeUKeyData(keyname, (unsigned char *)keydata, datalen); |
| if (tmp_ret != datalen) { |
| return -1; |
| } |
| return 0; |
| } |
| |
| int key_unify_read(const char* keyname, void* keydata, const unsigned bufLen) { |
| if (readUKeyData(keyname, (unsigned char *)keydata, CC_ONE_SECTION_SIZE) <= 0) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| int key_unify_query_size(const char* keyname, ssize_t *keysize) { |
| int rd_size = 0; |
| |
| rd_size = readUKeyData(keyname, gTempBuf, CC_ONE_SECTION_SIZE); |
| if (rd_size > 0) { |
| *keysize = rd_size; |
| return 0; |
| } |
| |
| return -1; |
| } |
| |
| int key_unify_query_exist(const char* keyname, int *exist) { |
| if (checkKeyNameInList(keyname) < 0) { |
| ALOGE("%s, key \"%s\" isn't exist in unifykeys list\n", __FUNCTION__, keyname); |
| *exist = 0; |
| return -1; |
| } |
| |
| *exist = 1; |
| return 0; |
| } |
| |
| int key_unify_query_secure(const char* keyname, int *isSecure) { |
| *isSecure = 0; |
| return 0; |
| } |
| |
| #endif |
| |
| #endif //CC_INI_IO_UKEY_USE_OTHER_MODULE |