blob: 7827b0ca055f27bae62f7a190c6a658aeeb768f5 [file] [log] [blame]
/*
* drivers/amlogic/unifykey/storagekey.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.
*
*/
/* extern from bl31 */
/*
* when RET_OK
* query: retval=1: key exsit,=0: key not exsit;
* tell: retvak = key size
* status: retval=1: secure, retval=0: non-secure
*/
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/scatterlist.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include <linux/kallsyms.h>
#include <linux/amlogic/efuse.h>
#include <linux/amlogic/unifykey/security_key.h>
#include <linux/amlogic/unifykey/key_manage.h>
#include <linux/of.h>
#include "unifykey.h"
#include "amlkey_if.h"
/* key buffer status */
/* bit0, dirty flag*/
#define KEYBUFFER_CLEAN (0 << 0)
#define KEYBUFFER_DIRTY (1 << 0)
#define SECUESTORAGE_HEAD_SIZE (256)
#define SECUESTORAGE_WHOLE_SIZE (0x40000)
#define OTHER_METHOD_CALL
#undef pr_fmt
#define pr_fmt(fmt) "unifykey: " fmt
struct storagekey_info_t {
uint8_t *buffer;
uint32_t size;
uint32_t status;
};
static struct storagekey_info_t storagekey_info = {
.buffer = NULL,
/* default size */
.size = SECUESTORAGE_WHOLE_SIZE,
.status = KEYBUFFER_CLEAN,
};
store_key_ops store_key_read;
store_key_ops store_key_write;
#ifndef OTHER_METHOD_CALL
int store_operation_init(void)
{
int ret = 0;
if (kallsyms_lookup_name("nand_key_read")) {
pr_info(" %s() nand storeage ops!\n", __func__);
store_key_read = nand_key_read;
store_key_write = nand_key_write;
} else if (kallsyms_lookup_name("emmc_key_read")) {
pr_info(" %s() emmc storeage ops!\n", __func__);
store_key_read = emmc_key_read;
store_key_write = emmc_key_write;
} else {
ret = -1;
pr_err(" %s() fail!\n", __func__);
}
return ret;
}
#endif
void storage_ops_read(store_key_ops read)
{
#ifdef OTHER_METHOD_CALL
store_key_read = read;
#endif
}
EXPORT_SYMBOL(storage_ops_read);
void storage_ops_write(store_key_ops write)
{
#ifdef OTHER_METHOD_CALL
store_key_write = write;
#endif
}
EXPORT_SYMBOL(storage_ops_write);
/**
*1.init
* return ok 0, fail 1
*/
int32_t amlkey_init_gen(uint8_t *seed, uint32_t len, int encrypt_type)
{
int32_t ret = 0;
uint32_t actual_size = 0;
#ifndef OTHER_METHOD_CALL
ret = store_operation_init();
if (ret < 0) {
ret = -1;
pr_err(" %s store_operation_init fail!\n", __func__);
goto _out;
}
#endif
/* do nothing for now*/
pr_info("%s() enter!\n", __func__);
if (storagekey_info.buffer != NULL) {
pr_err("%s() %d: already init!\n", __func__, __LINE__);
goto _out;
}
/* get buffer from bl31 */
storagekey_info.buffer =
secure_storage_getbuffer(&storagekey_info.size);
if (storagekey_info.buffer == NULL) {
pr_err("%s() %d: can't get buffer from bl31!\n",
__func__, __LINE__);
ret = -1;
goto _out;
}
/* full fill key infos from storage. */
if (store_key_read) {
ret = store_key_read(storagekey_info.buffer,
storagekey_info.size, &actual_size);
if (ret != 0) {
pr_err("fail to read key data\n");
memset(storagekey_info.buffer, 0,
SECUESTORAGE_HEAD_SIZE);
ret = -1;
goto _out;
}
if (actual_size >= (1U << 20)) {
pr_err("really need more than 1M mem? please check\n");
memset(storagekey_info.buffer, 0,
SECUESTORAGE_HEAD_SIZE);
ret = -1;
goto _out;
}
} else {
pr_err("store_key_read is NULL\n");
pr_err("check whether emmc_key/nand_key driver is enabled\n");
ret = -1;
goto _out;
}
storagekey_info.size = actual_size;
pr_info("%s() storagekey_info.buffer=%p, storagekey_info.size = %0x!\n",
__func__,
storagekey_info.buffer,
storagekey_info.size);
_out:
return ret;
}
int32_t amlkey_init_m8b(uint8_t *seed, uint32_t len, int encrypt_type)
{
int32_t ret = 0;
uint32_t actual_size = 0;
#ifndef OTHER_METHOD_CALL
ret = store_operation_init();
if (ret < 0) {
ret = -1;
pr_err(" %s store_operation_init fail!\n", __func__);
goto _out;
}
#endif
/* do nothing for now*/
pr_info("%s() enter!\n", __func__);
if (storagekey_info.buffer != NULL) {
pr_err("%s() %d: already init!\n", __func__, __LINE__);
goto _out;
}
if ((void *)kallsyms_lookup_name("nand_key_read")
== (void *)store_key_read)
secure_storage_type(0);
else
secure_storage_type(1);
/* get buffer from bl31 */
storagekey_info.buffer =
secure_storage_getbuffer(&storagekey_info.size);
if (storagekey_info.buffer == NULL) {
pr_err("%s() %d: can't get buffer from bl31!\n",
__func__, __LINE__);
ret = -1;
goto _out;
}
if (encrypt_type == -1)
encrypt_type = 0;
secure_storage_set_enctype(encrypt_type);
/* full fill key infos from storage. */
if (store_key_read) {
ret = store_key_read(storagekey_info.buffer,
storagekey_info.size, &actual_size);
if (ret != 0) {
pr_err("fail to read key data\n");
memset(storagekey_info.buffer, 0,
SECUESTORAGE_HEAD_SIZE);
ret = -1;
goto _out;
}
if (actual_size >= (1U << 20)) {
pr_err("really need more than 1M mem? please check\n");
memset(storagekey_info.buffer, 0,
SECUESTORAGE_HEAD_SIZE);
ret = -1;
goto _out;
}
} else {
pr_err("store_key_read is NULL\n");
pr_err("check whether emmc_key/nand_key driver is enabled\n");
ret = -1;
goto _out;
}
storagekey_info.size = actual_size;
pr_info("%s() storagekey_info.buffer=%p, storagekey_info.size = %0x!\n",
__func__,
storagekey_info.buffer,
storagekey_info.size);
storagekey_info.size = actual_size;
secure_storage_notifier_ex(actual_size);
_out:
return ret;
}
/**
*2. query if the key already programmed
* return: exsit 1, non 0
*/
int32_t amlkey_isexsit(const uint8_t *name)
{
int32_t ret = 0;
uint32_t retval;
if (name == NULL) {
pr_err("%s() %d, invalid key ", __func__, __LINE__);
return 0;
}
ret = secure_storage_query((uint8_t *)name, &retval);
if (ret) {
pr_err("%s() %d: ret %d\n", __func__, __LINE__, ret);
retval = 0;
}
return (int32_t)retval;
}
/**
* 3. query if the prgrammed key is secure
* return secure 1, non 0;
*/
int32_t amlkey_get_attr(const uint8_t *name)
{
int32_t ret = 0;
uint32_t retval;
if (name == NULL) {
pr_err("%s() %d, invalid key ", __func__, __LINE__);
return 0;
}
ret = secure_storage_status((uint8_t *)name, &retval);
if (ret) {
pr_err("%s() %d: ret %d\n", __func__, __LINE__, ret);
retval = 0;
}
return (int32_t)retval;
}
/**
* 3.1 query if the prgrammed key is secure
* return secure 1, non 0;
*/
int32_t amlkey_issecure(const uint8_t *name)
{
return amlkey_get_attr(name) & KEY_UNIFY_ATTR_SECURE_MASK;
}
/**
* 3.2 query if the prgrammed key is encrypt
* return encrypt 1, non 0;
*/
int32_t amlkey_isencrypt(const uint8_t *name)
{
return amlkey_get_attr(name) & KEY_UNIFY_ATTR_ENCRYPT_MASK;
}
/**
* 4. actual bytes of key value
* return actual size.
*/
ssize_t amlkey_size(const uint8_t *name)
{
ssize_t size = 0;
int32_t ret = 0;
uint32_t retval;
if (name == NULL) {
pr_err("%s() %d, invalid key ", __func__, __LINE__);
return 0;
}
ret = secure_storage_tell((uint8_t *)name, &retval);
if (ret) {
pr_err("%s() %d: ret %d\n", __func__, __LINE__, ret);
retval = 0;
}
size = (ssize_t)retval;
return size;
}
/**
*5. read non-secure key in bytes, return bytes readback actully.
* return actual size read back.
*/
ssize_t amlkey_read(const uint8_t *name, uint8_t *buffer, uint32_t len)
{
int32_t ret = 0;
ssize_t retval = 0;
uint32_t actul_len;
if (name == NULL) {
pr_err("%s() %d, invalid key ", __func__, __LINE__);
return 0;
}
ret = secure_storage_read((uint8_t *)name, buffer, len, &actul_len);
if (ret) {
pr_err("%s() %d: return %d\n", __func__, __LINE__, ret);
retval = 0;
goto _out;
}
retval = actul_len;
_out:
return retval;
}
/**
* 6.write key with attr in bytes , return bytes readback actully
* attr: bit0, secure/non-secure
* bit8, encrypt/non-encrypt
* return actual size write down.
*/
ssize_t amlkey_write(const uint8_t *name,
uint8_t *buffer,
uint32_t len,
uint32_t attr)
{
int32_t ret = 0;
ssize_t retval = 0;
uint32_t actual_length;
uint8_t *buf = NULL;
if (name == NULL) {
pr_err("%s() %d, invalid key ", __func__, __LINE__);
return retval;
}
pr_info("%s %d\n", __func__, __LINE__);
ret = secure_storage_write((uint8_t *)name,
buffer, len,
attr);
if (ret) {
pr_err("%s() %d: return %d\n", __func__, __LINE__, ret);
retval = 0;
goto _out;
} else {
retval = (ssize_t)len;
/* write down! */
if (storagekey_info.buffer != NULL) {
buf = kmalloc(storagekey_info.size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
memcpy(buf, storagekey_info.buffer,
storagekey_info.size);
if (store_key_write)
ret = store_key_write(buf,
storagekey_info.size,
&actual_length);
if (ret) {
pr_err("%s() %d, store_key_write fail\n",
__func__, __LINE__);
retval = 0;
}
kfree(buf);
}
}
_out:
return retval;
}
/**
* 7. get the hash value of programmed secure key | 32bytes length, sha256
* return success 0, fail -1
*/
int32_t amlkey_hash_4_secure(const uint8_t *name, uint8_t *hash)
{
int32_t ret = 0;
ret = secure_storage_verify((uint8_t *)name, hash);
return ret;
}
/**
* 7. del key by name
* return success 0, fail -1
*/
int32_t amlkey_del(const uint8_t *name)
{
int32_t ret = 0;
uint32_t actual_length;
if ((ret == 0) && (storagekey_info.buffer != NULL)) {
/* flush back */
if (store_key_write)
ret = store_key_write(storagekey_info.buffer,
storagekey_info.size, &actual_length);
if (ret) {
pr_err("%s() %d, store_key_write fail\n",
__func__,
__LINE__);
}
} else {
pr_err("%s() %d, remove key fail\n",
__func__,
__LINE__);
}
return ret;
}