blob: 12179e0a24b64767867381ad04787c49503845df [file] [log] [blame]
/*
* =====================================================================================
*
* Filename: v2_download_key.c
*
* Version: 1.0
* Created: 2013/9/4 14:10:07
* Compiler: gcc
*
* Author: Sam Wu (yihui.wu@amlogic.com)
* Organization: Amlogic Inc.
*
* Revision: none
* Description: Funcitions and command to burn keys with key_unify driver
*
* =====================================================================================
*/
#include "../v2_burning_i.h"
#include <amlogic/keyunify.h>
#ifndef CMD_BUFF_SIZE
#define CMD_BUFF_SIZE (512)
#endif// #ifndef CMD_BUFF_SIZE
#ifndef __HDCP22_HEY_H__
#define __HDCP22_HEY_H__
typedef unsigned int __u32;
typedef signed int __s32;
typedef unsigned char __u8;
typedef signed char __s8;
#define IH_MAGIC 0x27051956 /* Image Magic Number */
#define IH_NMLEN 32 /* Image Name Length */
#define AML_RES_IMG_ITEM_ALIGN_SZ 16
#define AML_RES_IMG_V1_MAGIC_LEN 8
#define AML_RES_IMG_V1_MAGIC "AML_HDK!"//8 chars
#define AML_RES_IMG_HEAD_SZ (24)//64
#define AML_RES_ITEM_HEAD_SZ (48)//64
#define AML_RES_IMG_VERSION_V1 (0x01)
#pragma pack(push, 1)
typedef struct pack_header{
unsigned int totalSz;/* Item Data total Size*/
unsigned int dataSz; /* Item Data used Size*/
unsigned int dataOffset; /* Item data offset*/
unsigned char type; /* Image Type, not used yet*/
unsigned char comp; /* Compression Type */
unsigned short reserv;
char name[IH_NMLEN]; /* Image Name */
}AmlResItemHead_t;
#pragma pack(pop)
//typedef for amlogic resource image
#pragma pack(push, 4)
typedef struct {
__u32 crc; //crc32 value for the resouces image
__s32 version;//0x01 means 'AmlResItemHead_t' attach to each item , 0x02 means all 'AmlResItemHead_t' at the head
__u8 magic[AML_RES_IMG_V1_MAGIC_LEN]; //resources images magic
__u32 imgSz; //total image size in byte
__u32 imgItemNum;//total item packed in the image
}AmlResImgHead_t;
#pragma pack(pop)
/*The Amlogic resouce image is consisted of a AmlResImgHead_t and many
*
* |<---AmlResImgHead_t-->|<--AmlResItemHead_t-->---...--|<--AmlResItemHead_t-->---...--|....
*
*/
#endif//#ifndef __HDCP22_HEY_H__
#define _AML_HDCP22_RX_KEY_NAME "aml_hdcp_key2.2"
static struct {
const char* keyName;
int isEncrypt;
}
_amlHdcp22RxKeys[] = {
[0] = {.keyName = "hdcp22_rx_private", .isEncrypt = 1},
[1] = {.keyName = "hdcp22_rx_fw", .isEncrypt = 0},
[2] = {.keyName = "hdcp2_rx", .isEncrypt = 0},
};
static char generalDataChange(const char input)
{
int i;
char result = 0;
for (i=0; i<8; i++) {
if ((input & (1<<i)) != 0)
result |= (1<<(7-i));
else
result &= ~(1<<(7-i));
}
return result;
}
static void hdcp2DataDecryption(const unsigned len, const char *input, char *out)
{
int i = 0;
for (i=0; i<len; i++)
out[i] = generalDataChange(input[i]);
}
/*
*This fucntion called by mwrite command, mread= bulkcmd "download key .." + n * download transfer, for key n==1
*Attentions: "return value is the key length" if burn sucess
*@keyName: key name in null-terminated c style string
*@keyVal: key value download from USB, "the value for sepecial keyName" may need de-encrypt by user code
*@keyValLen: the key value downloaded from usb transfer!
*@errInfo: start it with success if burned ok, or format error info into it tell pc burned failed
*/
unsigned v2_key_burn(const char* keyName, const u8* keyVal, const unsigned keyValLen, char* errInfo)
{
int ret = 0;
unsigned writtenLen = 0;
DWN_DBG("to write key[%s] in len=%d\n", keyName, keyValLen);
if (!strcmp(keyName, _AML_HDCP22_RX_KEY_NAME))
{
const AmlResImgHead_t* packedImgHead = (AmlResImgHead_t*)keyVal;
const AmlResItemHead_t* packedImgItem = (AmlResItemHead_t*)(packedImgHead + 1);
int i = 0;
const unsigned gensum = add_sum(keyVal + 4, keyValLen - 4);
if (packedImgHead->crc != gensum) {
DWN_ERR("crc chcked failed, origsum[%8x] != gensum[%8x]\n", packedImgHead->crc, gensum);
return 0;
}
for (i = 0; i < packedImgHead->imgItemNum; ++i)
{
const AmlResItemHead_t* pItem = packedImgItem + i;
const char* itemN = _amlHdcp22RxKeys[i].keyName;
u8* itembuf = (u8*)keyVal + pItem->dataOffset;
int itemSz = pItem->dataSz;
if (_amlHdcp22RxKeys[i].isEncrypt) {
DWN_MSG("key[%s] at[%d] isEncrypted\n", itemN, i);
hdcp2DataDecryption(itemSz, (char*)itembuf, (char*)itembuf);
}
DWN_MSG("burnkey[%s] at sz[%d]\n", itemN, itemSz);
ret = key_manage_write(itemN, itembuf, itemSz);
if (ret) {
DWN_ERR("Fail to write key[%s] in len=%d\n", itemN, itemSz);
return 0;
}
}
}
else
{
ret = key_manage_write(keyName, keyVal, keyValLen);
if (ret) {
DWN_ERR("Fail to write key[%s] in len=%d\n", keyName, keyValLen);
return 0;
}
}
writtenLen = ret >=0 ? keyValLen : 0;
return writtenLen;
}
/*
*This fucntion called by mread command, mread= bulkcmd "upload key .." + n * upload transfer, for key n==1
*Attentions: return 0 if success, else failed
*@keyName: key name in null-terminated c style string
*@keyVal: the buffer to read back the key value
*@keyValLen: keyVal len is strict when read, i.e, user must know the length of key he/she wnat to read!!
*@errInfo: start it with success if burned ok, or format error info into it tell pc burned failed
*/
int v2_key_read(const char* keyName, u8* keyVal, const unsigned keyValLen, char* errInfo, unsigned* fmtLen)
{
ssize_t keysize = 0;
int rc = 0;
rc = key_manage_query_size(keyName, &keysize);
if (rc) {
sprintf(errInfo, "failed to query key size, err=%d\n", rc);
DWN_ERR(errInfo);
return __LINE__;
}
rc = key_manage_read(keyName, keyVal, keyValLen);
*fmtLen = (unsigned)keysize;
return rc;
}
//key command: 1, key init seed_in_str; 2, key uninit
//argv[0] can be 'key' from usb tool, or 'aml_key_burn/misc' from sdc_burn
int v2_key_command(const int argc, char * const argv[], char *info)
{
const char* keyCmd = argv[1];
int rcode = 0;
int subCmd_argc = argc - 1;
char* const * subCmd_argv = argv + 1;
DWN_DBG("argc=%d, argv[%s, %s, %s, %s]\n", argc, argv[0], argv[1], argv[2], argv[3]);
if (argc < 2) {
sprintf(info, "argc < 2, need key subcmd\n");
DWN_ERR(info);
return __LINE__;
}
if (!strcmp("init", keyCmd))
{
if (argc < 3) {
sprintf(info, "failed:cmd [key init] must take argument (seedNum)\n");
DWN_ERR(info);
return __LINE__;
}
rcode = key_manage_init(subCmd_argv[1], subCmd_argv[2]);
}
else if(!strcmp("uninit", keyCmd))
{
rcode = key_manage_exit();
}
else if(!strcmp("is_burned", keyCmd))
{
if (subCmd_argc < 2) {
sprintf(info, "failed: %s %s need a keyName\n", argv[0], argv[1]);
DWN_ERR(info);
return __LINE__;
}
const char* queryKey = subCmd_argv[1];
int keyIsBurned = 0;
if (!strcmp(_AML_HDCP22_RX_KEY_NAME, queryKey)) queryKey = _amlHdcp22RxKeys[0].keyName;
rcode = key_manage_query_exist(queryKey, &keyIsBurned);
if (rcode) {
sprintf(info, "failed to query key state, rcode %d\n", rcode);
DWN_ERR(info);
return __LINE__;
}
sprintf(info, "%s:key[%s] was %s burned", keyIsBurned ? "success" : "failed",
queryKey, keyIsBurned ? "" : "NOT");
rcode = !keyIsBurned;
}
else if(!strcmp("can_write", keyCmd))
{
if (subCmd_argc < 2) {
sprintf(info, "failed: %s %s need a keyName\n", argv[0], argv[1]);
DWN_ERR(info);
return __LINE__;
}
const char* queryKey = subCmd_argv[1];
int exist = 0;
int canOverWrite = 0;
if (!strcmp(_AML_HDCP22_RX_KEY_NAME, queryKey)) queryKey = _amlHdcp22RxKeys[0].keyName;
rcode = key_manage_query_canOverWrite(queryKey, &canOverWrite);
if (rcode) {
sprintf(info, "failed in query key over write, rcode %d\n", rcode);
DWN_ERR(info);
return __LINE__;
}
rcode = key_manage_query_exist(queryKey, &exist);
if (rcode) {
sprintf(info, "failed in query key exist, rcode %d\n", rcode);
DWN_ERR(info);
return __LINE__;
}
int canWrite = ! (exist && !canOverWrite);
sprintf(info, "%s:key[%s] %s can write(exist=%d, canOverWrite=%d)\n",
canWrite ? "success" : "failed", queryKey, canWrite ? "" : "NOT", exist, canOverWrite);
rcode = !canWrite;
}
else if(!strcmp("can_read", keyCmd))
{
int isSecure = 0;
int exist = 0;
const char* queryKey = subCmd_argv[1];
rcode = key_manage_query_exist(queryKey, &exist);
if (rcode) {
sprintf(info, "failed in query key exist, rcode %d\n", rcode);
DWN_ERR(info);
return __LINE__;
}
rcode = key_manage_query_secure(queryKey,&isSecure);
if (rcode) {
sprintf(info, "failed in query key secure, rcode %d\n", rcode);
DWN_ERR(info);
return __LINE__;
}
sprintf(info, "%s:key[%s] %s can read\n",
isSecure ? "failed" : "success", queryKey, isSecure ? "NOT" : "");
rcode = isSecure;
}
else if(!strcmp("write", keyCmd))
{
const char* keyName = subCmd_argv[1];
const char* keyValInStr = subCmd_argv[2];
if (subCmd_argc < 3) {
sprintf(info, "failed: %s %s need a keyName and keyValInStr\n", argv[0], argv[1]);
DWN_ERR(info);
return __LINE__;
}
rcode = v2_key_burn(keyName, (u8*)keyValInStr, strlen(keyValInStr), info);
rcode = (strlen(keyValInStr) == rcode) ? 0 : __LINE__;
}
else if(!strcmp("read", keyCmd))
{
const char* keyName = subCmd_argv[1];
const int cswBufLen = CMD_BUFF_SIZE - sizeof("success") + 1;
unsigned char* keyValBuf = (unsigned char*)info + CMD_BUFF_SIZE - cswBufLen;
if (subCmd_argc < 2) {
sprintf(info, "failed: %s %s need a keyName\n", argv[0], argv[1]);
DWN_ERR(info);
return __LINE__;
}
sprintf(info, "keyman read %s 0x%p str", keyName, keyValBuf);
rcode = run_command(info, 0);
if (!rcode)
sprintf(info, "success:%s=[%s]", keyName, getenv(keyName));
else
sprintf(info, "failed in read key");
}
else if(!strcmp("get_len", keyCmd))
{
ssize_t keySz = 0;
const char* queryKey = subCmd_argv[1];
rcode = key_manage_query_size(queryKey,&keySz);
if (rcode) {
sprintf(info, "failed in query key size, rcode %d\n", rcode);
DWN_ERR(info);
return __LINE__;
}
sprintf(info, "success%zd\n", keySz);
rcode = !keySz;
}
else{
sprintf(info, "failed:Error keyCmd[%s]\n", keyCmd);
DWN_ERR(info);
rcode = __LINE__;
}
DWN_DBG("rcode 0x%x\n", rcode);
return rcode;
}