mirror of
https://github.com/brain-hackers/linux-brain.git
synced 2024-06-09 23:36:23 +09:00
MLK-24420-2 crypto: caam - add support for black keys and blobs
CAAM's Black Key mechanism is intended for protection of user keys against bus snooping. This automatically encapsulates and decapsulates cryptographic keys ''on-the-fly'' in an encrypted data structure called a Black Key. Before a value is copied from a Key Register to memory, CAAM will automatically encrypt the key as a Black Key (encrypted key) using the current value in the JDKEKR or TDKEKR as the encryption key. CAAM's built-in Blob Protocol provides a method for protecting user-defined data across system power cycles. CAAM protects data in a data structure called a Blob, which provides both confidentiality and integrity protection. The data to be protected is encrypted so that it can be safely placed into non-volatile storage before the SoC is powered down. This patch includes the support to generate a black key from random or from a plaintext. Also one can encapsulate it into a blob or decapsulate a black key from a blob. The key and blob generation descriptors are exported into a separate file, such that they could be shared with other interfaces (qi, qi2). This feature has support only for black keys, encapsulated in black blobs in General Memory. In caamkeyblob_test.c file is a test that validates the above operations: create a black key from plaintext or from random, encapsulate and decapsulate a blob and compare the obtained black key. This test is configured as a kernel module. Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com> Signed-off-by: Iuliana Prodan <iuliana.prodan@nxp.com> Reviewed-by: Horia Geantă <horia.geanta@nxp.com>
This commit is contained in:
parent
04cab5a13d
commit
84287c5d3b
|
@ -8,6 +8,9 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC
|
|||
config CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC
|
||||
tristate
|
||||
|
||||
config CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC
|
||||
tristate
|
||||
|
||||
config CRYPTO_DEV_FSL_CAAM_SECVIO
|
||||
tristate "CAAM/SNVS Security Violation Handler (EXPERIMENTAL)"
|
||||
depends on ARCH_MXC
|
||||
|
@ -158,12 +161,25 @@ config CRYPTO_DEV_FSL_CAAM_RNG_API
|
|||
|
||||
config CRYPTO_DEV_FSL_CAAM_TK_API
|
||||
bool "Register tagged key cryptography implementations with Crypto API"
|
||||
default y
|
||||
select CRYPTO_DEV_FSL_CAAM_CRYPTO_API
|
||||
select CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC
|
||||
help
|
||||
Selecting this will register algorithms supporting tagged key.
|
||||
Selecting this will register algorithms supporting tagged key and
|
||||
generate black keys and encapsulate them into black blobs.
|
||||
|
||||
Tagged keys are keys that contain metadata indicating what
|
||||
Tagged keys are black keys that contain metadata indicating what
|
||||
they are and how to handle them.
|
||||
CAAM protects data in a data structure called a Blob, which provides
|
||||
both confidentiality and integrity protection.
|
||||
|
||||
config CRYPTO_DEV_FSL_CAAM_TK_API_TEST
|
||||
tristate "CAAM keys and blobs test"
|
||||
depends on CRYPTO_DEV_FSL_CAAM_TK_API
|
||||
depends on m
|
||||
help
|
||||
Test to exercise black key generation and blob encapsulation and
|
||||
decapsulation.
|
||||
|
||||
config CRYPTO_DEV_FSL_CAAM_RNG_TEST
|
||||
bool "Test caam rng"
|
||||
|
|
|
@ -13,11 +13,12 @@ obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o
|
|||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o
|
||||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o
|
||||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API_DESC) += caamhash_desc.o
|
||||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_KEYBLOB_API_DESC) += caamkeyblob_desc.o
|
||||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR_UIO) += fsl_jr_uio.o
|
||||
|
||||
caam-y := ctrl.o
|
||||
caam_jr-y := jr.o key_gen.o
|
||||
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) += tag_object.o
|
||||
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API) += tag_object.o caamkeyblob.o
|
||||
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
|
||||
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
|
||||
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
|
||||
|
@ -26,6 +27,7 @@ caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o
|
|||
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM) += sm_store.o
|
||||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SM_TEST) += sm_test.o
|
||||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_SECVIO) += secvio.o
|
||||
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_TK_API_TEST) += caamkeyblob_test.o
|
||||
|
||||
caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
|
||||
ifneq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI),)
|
||||
|
|
696
drivers/crypto/caam/caamkeyblob.c
Normal file
696
drivers/crypto/caam/caamkeyblob.c
Normal file
|
@ -0,0 +1,696 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
||||
/*
|
||||
* Black key generation and blob encapsulation/decapsulation for CAAM
|
||||
*
|
||||
* Copyright 2018-2020 NXP
|
||||
*/
|
||||
#include "caamkeyblob.h"
|
||||
#include "error.h"
|
||||
|
||||
/* Black key generation and blob encap/decap job completion handler */
|
||||
static void caam_key_blob_done(struct device *dev, u32 *desc, u32 err,
|
||||
void *context)
|
||||
{
|
||||
struct jr_job_result *res = context;
|
||||
int ecode = 0;
|
||||
|
||||
dev_dbg(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
|
||||
|
||||
if (err)
|
||||
ecode = caam_jr_strstatus(dev, err);
|
||||
|
||||
/* Save the error for post-processing */
|
||||
res->error = ecode;
|
||||
/* Mark job as complete */
|
||||
complete(&res->completion);
|
||||
}
|
||||
|
||||
/**
|
||||
* map_write_data - Prepare data to be written to CAAM
|
||||
*
|
||||
* @dev : struct device of the job ring to be used
|
||||
* @data : The data to be prepared
|
||||
* @size : The size of data to be prepared
|
||||
* @dma_addr : The retrieve DMA address of the input data
|
||||
* @allocated_data : Pointer to a DMA-able address where the input
|
||||
* data is copied and synchronized
|
||||
*
|
||||
* Return : '0' on success, error code otherwise
|
||||
*/
|
||||
static int map_write_data(struct device *dev, const u8 *data, size_t size,
|
||||
dma_addr_t *dma_addr, u8 **allocated_data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Allocate memory for data and copy it to DMA zone */
|
||||
*allocated_data = kmemdup(data, size, GFP_KERNEL | GFP_DMA);
|
||||
if (!*allocated_data) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*dma_addr = dma_map_single(dev, *allocated_data, size, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(dev, *dma_addr)) {
|
||||
dev_err(dev, "Unable to map write data\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_alloc;
|
||||
}
|
||||
|
||||
goto exit;
|
||||
|
||||
free_alloc:
|
||||
kfree(*allocated_data);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* map_read_data - Prepare data to be read from CAAM
|
||||
*
|
||||
* @dev : struct device of the job ring to be used
|
||||
* @size : The size of data to be prepared
|
||||
* @dma_addr : The retrieve DMA address of the data to be read
|
||||
* @allocated_data : Pointer to a DMA-able address where the data
|
||||
* to be read will be copied and synchronized
|
||||
*
|
||||
* Return : '0' on success, error code otherwise
|
||||
*/
|
||||
static int map_read_data(struct device *dev, size_t size, dma_addr_t *dma_addr,
|
||||
u8 **allocated_data)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Allocate memory for data compatible with DMA */
|
||||
*allocated_data = kmalloc(size, GFP_KERNEL | GFP_DMA);
|
||||
if (!*allocated_data) {
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
*dma_addr = dma_map_single(dev, *allocated_data, size, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dev, *dma_addr)) {
|
||||
dev_err(dev, "Unable to map read data\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_alloc;
|
||||
}
|
||||
|
||||
goto exit;
|
||||
|
||||
free_alloc:
|
||||
kfree(*allocated_data);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* read_map_data - Read the data from CAAM
|
||||
*
|
||||
* @dev : struct device of the job ring to be used
|
||||
* @data : The read data from CAAM will be copied here
|
||||
* @dma_addr : The DMA address of the data to be read
|
||||
* @allocated_data : Pointer to a DMA-able address where the data
|
||||
* to be read is
|
||||
* @size : The size of data to be read
|
||||
*/
|
||||
static void read_map_data(struct device *dev, u8 *data, dma_addr_t dma_addr,
|
||||
u8 *allocated_data, size_t size)
|
||||
{
|
||||
/* Synchronize the DMA and copy the data */
|
||||
dma_sync_single_for_cpu(dev, dma_addr, size, DMA_FROM_DEVICE);
|
||||
memcpy(data, allocated_data, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* unmap_read_write_data - Unmap the data needed for or from CAAM
|
||||
*
|
||||
* @dev : struct device of the job ring to be used
|
||||
* @dma_addr : The DMA address of the data used for DMA transfer
|
||||
* @allocated_data : The data used for DMA transfer
|
||||
* @size : The size of data
|
||||
* @dir : The DMA_API direction
|
||||
*/
|
||||
static void unmap_read_write_data(struct device *dev, dma_addr_t dma_addr,
|
||||
u8 *allocated_data, size_t size,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
/* Free the resources and clear the data*/
|
||||
dma_unmap_single(dev, dma_addr, size, dir);
|
||||
kzfree(allocated_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_caam_dma_addr - Get the CAAM DMA address of a physical address.
|
||||
*
|
||||
* @phy_address : The physical address
|
||||
*
|
||||
* Return : The CAAM DMA address
|
||||
*/
|
||||
static dma_addr_t get_caam_dma_addr(const void *phy_address)
|
||||
{
|
||||
uintptr_t ptr_conv;
|
||||
dma_addr_t caam_dma_address = 0;
|
||||
|
||||
/* Check if conversion is possible */
|
||||
if (sizeof(caam_dma_address) < sizeof(phy_address)) {
|
||||
/*
|
||||
* Check that all bits sets in the phy_address
|
||||
* can be stored in caam_dma_address
|
||||
*/
|
||||
|
||||
/* Generate a mask of the representable bits */
|
||||
u64 mask = GENMASK_ULL(sizeof(caam_dma_address) * 8 - 1, 0);
|
||||
|
||||
/*
|
||||
* Check that the bits not representable of
|
||||
* the physical address are not set
|
||||
*/
|
||||
if ((uintptr_t)phy_address & ~mask)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Convert address to caam_dma_address */
|
||||
ptr_conv = (uintptr_t)phy_address;
|
||||
caam_dma_address = (dma_addr_t)ptr_conv;
|
||||
|
||||
exit:
|
||||
return caam_dma_address;
|
||||
}
|
||||
|
||||
/**
|
||||
* generate_black_key - Generate a black key from a plaintext or random,
|
||||
* based on the given input: a size for a random black
|
||||
* key, or a plaintext (input key).
|
||||
*
|
||||
* If the memory type is Secure Memory, the key to cover is read
|
||||
* directly by CAAM from Secure Memory without intermediate copy.
|
||||
* The value of the input key (plaintext) must be a physical address
|
||||
* in Secure Memory.
|
||||
*
|
||||
* Notes:
|
||||
* Limited to Class 1 keys, at the present time.
|
||||
* The input and output data are copied to temporary arrays
|
||||
* except for the input key if the memory type is Secure Memory.
|
||||
* For now, we have support for Black keys, stored in General Memory.
|
||||
*
|
||||
* @dev : struct device of the job ring to be used
|
||||
* @info : keyblob_info structure, will be updated with
|
||||
* the black key data from CAAM.
|
||||
* This contains, also, all the data necessary to generate
|
||||
* a black key from plaintext/random like: key encryption
|
||||
* key, memory type, input key, etc.
|
||||
*
|
||||
* Return : '0' on success, error code otherwise
|
||||
*/
|
||||
int generate_black_key(struct device *dev, struct keyblob_info *info)
|
||||
{
|
||||
int ret = 0;
|
||||
bool not_random = false;
|
||||
u8 trusted_key, key_enc;
|
||||
u32 *desc = NULL;
|
||||
size_t black_key_length_req = 0;
|
||||
dma_addr_t key_dma, black_key_dma;
|
||||
u8 *tmp_key = NULL, *tmp_black_key = NULL;
|
||||
|
||||
/* Validate device */
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If an input key (plaintext) is given,
|
||||
* generate a black key from it, not from random
|
||||
*/
|
||||
if (info->key)
|
||||
not_random = true;
|
||||
|
||||
/* Get trusted key and key encryption type from type */
|
||||
trusted_key = (info->type >> TAG_OBJ_TK_OFFSET) & 0x1;
|
||||
key_enc = (info->type >> TAG_OBJ_EKT_OFFSET) & 0x1;
|
||||
|
||||
dev_dbg(dev, "%s input: [key: (%zu) black_key: %p(%zu), key_enc: %x]\n",
|
||||
__func__, info->key_len, info->black_key, info->black_key_len,
|
||||
key_enc);
|
||||
if (not_random)
|
||||
print_hex_dump_debug("input key @" __stringify(__LINE__) ": ",
|
||||
DUMP_PREFIX_ADDRESS, 16, 4, info->key,
|
||||
info->key_len, 1);
|
||||
|
||||
/* Validate key type - only JDKEK keys are supported */
|
||||
if (!is_key_type(info->type) || is_trusted_type(info->type))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Validate key size, expected values are
|
||||
* between 16 and 64 bytes.
|
||||
* See TODO from cnstr_desc_black_key().
|
||||
*/
|
||||
if (info->key_len < MIN_KEY_SIZE || info->key_len > MAX_KEY_SIZE)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Based on key encryption type (ecb or ccm),
|
||||
* compute the black key size
|
||||
*/
|
||||
if (key_enc == KEY_COVER_ECB)
|
||||
/*
|
||||
* ECB-Black Key will be padded with zeros to make it a
|
||||
* multiple of 16 bytes long before it is encrypted,
|
||||
* and the resulting Black Key will be this length.
|
||||
*/
|
||||
black_key_length_req = ECB_BLACK_KEY_SIZE(info->key_len);
|
||||
else if (key_enc == KEY_COVER_CCM)
|
||||
/*
|
||||
* CCM-Black Key will always be at least 12 bytes longer,
|
||||
* since the encapsulation uses a 6-byte nonce and adds
|
||||
* a 6-byte ICV. But first, the key is padded as necessary so
|
||||
* that CCM-Black Key is a multiple of 8 bytes long.
|
||||
*/
|
||||
black_key_length_req = CCM_BLACK_KEY_SIZE(info->key_len);
|
||||
|
||||
/* Check if there is enough space for black key */
|
||||
if (info->black_key_len < black_key_length_req) {
|
||||
info->black_key_len = black_key_length_req;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Black key will have at least the same length as the input key */
|
||||
info->black_key_len = info->key_len;
|
||||
|
||||
dev_dbg(dev, "%s processing: [key: (%zu) black_key: %p(%zu)",
|
||||
__func__, info->key_len, info->black_key, info->black_key_len);
|
||||
dev_dbg(dev, "req:%zu, key_enc: 0x%x]\n", black_key_length_req, key_enc);
|
||||
|
||||
if (not_random) {
|
||||
/* Map input key, this will be sent to CAAM */
|
||||
if (map_write_data(dev, info->key, info->key_len,
|
||||
&key_dma, &tmp_key)) {
|
||||
dev_err(dev, "Unable to map input key\n");
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Map black key, this will be read from CAAM */
|
||||
if (map_read_data(dev, black_key_length_req,
|
||||
&black_key_dma, &tmp_black_key)) {
|
||||
dev_err(dev, "Unable to map black key\n");
|
||||
ret = -ENOMEM;
|
||||
goto unmap_input_key;
|
||||
}
|
||||
|
||||
/* Construct descriptor for black key */
|
||||
if (not_random)
|
||||
ret = cnstr_desc_black_key(&desc, key_dma, info->key_len,
|
||||
black_key_dma, info->black_key_len,
|
||||
key_enc, trusted_key);
|
||||
else
|
||||
ret = cnstr_desc_random_black_key(&desc, info->key_len,
|
||||
black_key_dma,
|
||||
info->black_key_len,
|
||||
key_enc, trusted_key);
|
||||
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed to construct the descriptor for black key\n");
|
||||
goto unmap_black_key;
|
||||
}
|
||||
|
||||
/* Execute descriptor and wait for its completion */
|
||||
ret = caam_jr_run_and_wait_for_completion(dev, desc,
|
||||
caam_key_blob_done);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to execute black key descriptor\n");
|
||||
goto free_desc;
|
||||
}
|
||||
|
||||
/* Read black key from CAAM */
|
||||
read_map_data(dev, info->black_key, black_key_dma,
|
||||
tmp_black_key, black_key_length_req);
|
||||
|
||||
/* Update black key length with the correct size */
|
||||
info->black_key_len = black_key_length_req;
|
||||
|
||||
free_desc:
|
||||
kfree(desc);
|
||||
|
||||
unmap_black_key:
|
||||
unmap_read_write_data(dev, black_key_dma, tmp_black_key,
|
||||
black_key_length_req, DMA_FROM_DEVICE);
|
||||
|
||||
unmap_input_key:
|
||||
if (not_random)
|
||||
unmap_read_write_data(dev, key_dma, tmp_key, info->key_len,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(generate_black_key);
|
||||
|
||||
/**
|
||||
* caam_blob_encap - Encapsulate a black key into a blob
|
||||
*
|
||||
* If the memory type is Secure Memory, the key to encapsulate is read
|
||||
* directly by CAAM from Secure Memory without intermediate copy.
|
||||
* The value of the key (black key) must be a physical address
|
||||
* in Secure Memory.
|
||||
*
|
||||
* Notes:
|
||||
* For now, we have support for Black keys, stored in General Memory and
|
||||
* encapsulated into black blobs.
|
||||
*
|
||||
* @dev : struct device of the job ring to be used
|
||||
* @info : keyblob_info structure, will be updated with
|
||||
* the blob data from CAAM.
|
||||
* This contains, also, all the data necessary to
|
||||
* encapsulate a black key into a blob: key encryption
|
||||
* key, memory type, color, etc.
|
||||
*
|
||||
* Return : '0' on success, error code otherwise
|
||||
*/
|
||||
int caam_blob_encap(struct device *dev, struct keyblob_info *info)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 *desc = NULL;
|
||||
size_t black_key_real_len = 0;
|
||||
u8 mem_type, color, key_enc, trusted_key;
|
||||
dma_addr_t black_key_dma, key_mod_dma, blob_dma;
|
||||
unsigned char *blob = info->blob + BLOB_HEADER_SIZE;
|
||||
u8 *tmp_black_key = NULL, *tmp_key_mod = NULL, *tmp_blob = NULL;
|
||||
|
||||
/* Validate device */
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Get memory type, trusted key, key encryption
|
||||
* type and color from type
|
||||
*/
|
||||
mem_type = (info->type >> TAG_OBJ_MEM_OFFSET) & 0x1;
|
||||
color = (info->type >> TAG_OBJ_COLOR_OFFSET) & 0x1;
|
||||
key_enc = (info->type >> TAG_OBJ_EKT_OFFSET) & 0x1;
|
||||
trusted_key = (info->type >> TAG_OBJ_TK_OFFSET) & 0x1;
|
||||
|
||||
/* Validate input data*/
|
||||
if (!info->black_key || !info->key_mod || !blob)
|
||||
return -EINVAL;
|
||||
|
||||
/* Validate object type - only JDKEK keys are supported */
|
||||
if (is_trusted_type(info->type))
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(dev, "%s input:[black_key: %p (%zu) color: %x, key_enc: %x",
|
||||
__func__, info->black_key, info->black_key_len, color, key_enc);
|
||||
dev_dbg(dev, ", key_mod: %p (%zu)", info->key_mod, info->key_mod_len);
|
||||
dev_dbg(dev, "blob: %p (%zu)]\n", blob, info->blob_len);
|
||||
|
||||
/*
|
||||
* Based on memory type, the key modifier length
|
||||
* can be 8-byte or 16-byte.
|
||||
*/
|
||||
if (mem_type == DATA_SECMEM)
|
||||
info->key_mod_len = KEYMOD_SIZE_SM;
|
||||
else
|
||||
info->key_mod_len = KEYMOD_SIZE_GM;
|
||||
|
||||
/* Adapt the size of the black key */
|
||||
black_key_real_len = info->black_key_len;
|
||||
|
||||
/* Check if the blob can be stored */
|
||||
if (info->blob_len < (black_key_real_len + BLOB_OVERHEAD))
|
||||
return -EINVAL;
|
||||
|
||||
/* Update the blob length */
|
||||
info->blob_len = black_key_real_len + BLOB_OVERHEAD;
|
||||
|
||||
dev_dbg(dev, "%s processing: [black_key: %p (%zu) cnstr: %zu",
|
||||
__func__, info->black_key, info->black_key_len,
|
||||
black_key_real_len);
|
||||
dev_dbg(dev, " color: %x key_enc: %x, mem_type: %x,",
|
||||
color, key_enc, mem_type);
|
||||
dev_dbg(dev, ", key_mod: %p (%zu) ", info->key_mod, info->key_mod_len);
|
||||
dev_dbg(dev, "blob: %p (%zu)]\n", blob, info->blob_len);
|
||||
|
||||
/* Map black key, this will be transferred to CAAM */
|
||||
if (mem_type == DATA_GENMEM) {
|
||||
if (map_write_data(dev, info->black_key, info->black_key_len,
|
||||
&black_key_dma, &tmp_black_key)) {
|
||||
dev_err(dev, "Unable to map black key for blob\n");
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
black_key_dma = get_caam_dma_addr(info->black_key);
|
||||
if (!black_key_dma)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Map key modifier, this will be sent to CAAM */
|
||||
if (mem_type == DATA_GENMEM) {
|
||||
if (map_write_data(dev, info->key_mod, info->key_mod_len,
|
||||
&key_mod_dma, &tmp_key_mod)) {
|
||||
dev_err(dev, "Unable to map key_mod for blob\n");
|
||||
ret = -ENOMEM;
|
||||
goto unmap_black_key;
|
||||
}
|
||||
} else {
|
||||
key_mod_dma = get_caam_dma_addr(info->key_mod);
|
||||
if (!key_mod_dma)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Map blob, this will be read to CAAM */
|
||||
if (mem_type == DATA_GENMEM) {
|
||||
if (map_read_data(dev, info->blob_len, &blob_dma, &tmp_blob)) {
|
||||
dev_err(dev, "Unable to map blob\n");
|
||||
ret = -ENOMEM;
|
||||
goto unmap_key_mod;
|
||||
}
|
||||
} else {
|
||||
blob_dma = get_caam_dma_addr(info->blob);
|
||||
if (!blob_dma)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Construct descriptor for blob encapsulation */
|
||||
ret = cnstr_desc_blob_encap(&desc, black_key_dma, black_key_real_len,
|
||||
color, key_enc, trusted_key, mem_type,
|
||||
key_mod_dma, info->key_mod_len,
|
||||
blob_dma, info->blob_len);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed to construct the descriptor for blob encap\n");
|
||||
goto unmap_blob;
|
||||
}
|
||||
|
||||
/* Execute descriptor and wait for its completion */
|
||||
ret = caam_jr_run_and_wait_for_completion(dev, desc,
|
||||
caam_key_blob_done);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to execute blob encap descriptor\n");
|
||||
goto free_desc;
|
||||
}
|
||||
|
||||
/* Read blob from CAAM */
|
||||
if (mem_type == DATA_GENMEM)
|
||||
read_map_data(dev, blob, blob_dma, tmp_blob, info->blob_len);
|
||||
|
||||
print_hex_dump_debug("blob @" __stringify(__LINE__) ": ",
|
||||
DUMP_PREFIX_ADDRESS, 16, 4, blob,
|
||||
info->blob_len, 1);
|
||||
free_desc:
|
||||
kfree(desc);
|
||||
|
||||
unmap_blob:
|
||||
if (mem_type == DATA_GENMEM)
|
||||
unmap_read_write_data(dev, blob_dma, tmp_blob,
|
||||
info->blob_len, DMA_FROM_DEVICE);
|
||||
|
||||
unmap_key_mod:
|
||||
if (mem_type == DATA_GENMEM)
|
||||
unmap_read_write_data(dev, key_mod_dma, tmp_key_mod,
|
||||
info->key_mod_len, DMA_TO_DEVICE);
|
||||
|
||||
unmap_black_key:
|
||||
if (mem_type == DATA_GENMEM)
|
||||
unmap_read_write_data(dev, black_key_dma, tmp_black_key,
|
||||
info->black_key_len, DMA_TO_DEVICE);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(caam_blob_encap);
|
||||
|
||||
/**
|
||||
* caam_blob_decap - Decapsulate a black key from a blob
|
||||
*
|
||||
* Notes:
|
||||
* For now, we have support for Black blob, stored in General Memory and
|
||||
* can be decapsulated into a black key.
|
||||
*
|
||||
* @dev : struct device of the job ring to be used
|
||||
* @info : keyblob_info structure, will be updated with
|
||||
* the black key decapsulated from the blob.
|
||||
* This contains, also, all the data necessary to
|
||||
* encapsulate a black key into a blob: key encryption
|
||||
* key, memory type, color, etc.
|
||||
*
|
||||
* Return : '0' on success, error code otherwise
|
||||
*/
|
||||
int caam_blob_decap(struct device *dev, struct keyblob_info *info)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 *desc = NULL;
|
||||
u8 mem_type, color, key_enc, trusted_key;
|
||||
size_t black_key_real_len;
|
||||
dma_addr_t key_mod_dma, black_key_dma, blob_dma;
|
||||
unsigned char *blob = info->blob + BLOB_HEADER_SIZE;
|
||||
u8 *tmp_black_key = NULL, *tmp_key_mod = NULL, *tmp_blob = NULL;
|
||||
|
||||
/* Validate device */
|
||||
if (!dev)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Get memory type, trusted key, key encryption
|
||||
* type and color from type
|
||||
*/
|
||||
mem_type = (info->type >> TAG_OBJ_MEM_OFFSET) & 0x1;
|
||||
color = (info->type >> TAG_OBJ_COLOR_OFFSET) & 0x1;
|
||||
key_enc = (info->type >> TAG_OBJ_EKT_OFFSET) & 0x1;
|
||||
trusted_key = (info->type >> TAG_OBJ_TK_OFFSET) & 0x1;
|
||||
|
||||
/* Validate input data*/
|
||||
if (!info->black_key || !info->key_mod || !blob)
|
||||
return -EINVAL;
|
||||
|
||||
dev_dbg(dev, "%s input: [blob: %p (%zu), mem_type: %x, color: %x",
|
||||
__func__, blob, info->blob_len, mem_type, color);
|
||||
dev_dbg(dev, " keymod: %p (%zu)", info->key_mod, info->key_mod_len);
|
||||
dev_dbg(dev, " secret: %p (%zu) key_enc: %x]\n",
|
||||
info->black_key, info->black_key_len, key_enc);
|
||||
|
||||
/* Validate object type - only JDKEK keys are supported */
|
||||
if (is_trusted_type(info->type))
|
||||
return -EINVAL;
|
||||
|
||||
print_hex_dump_debug("blob @" __stringify(__LINE__) ": ",
|
||||
DUMP_PREFIX_ADDRESS, 16, 4, blob,
|
||||
info->blob_len, 1);
|
||||
|
||||
/*
|
||||
* Based on memory type, the key modifier length
|
||||
* can be 8-byte or 16-byte.
|
||||
*/
|
||||
if (mem_type == DATA_SECMEM)
|
||||
info->key_mod_len = KEYMOD_SIZE_SM;
|
||||
else
|
||||
info->key_mod_len = KEYMOD_SIZE_GM;
|
||||
|
||||
/* Check if the blob is valid */
|
||||
if (info->blob_len <= BLOB_OVERHEAD)
|
||||
return -EINVAL;
|
||||
|
||||
/* Initialize black key length */
|
||||
black_key_real_len = info->blob_len - BLOB_OVERHEAD;
|
||||
|
||||
/* Check if the black key has enough space to be stored */
|
||||
if (info->black_key_len < black_key_real_len)
|
||||
return -EINVAL;
|
||||
|
||||
/* Update black key length with the one computed based on key_enc */
|
||||
info->black_key_len = black_key_real_len;
|
||||
|
||||
dev_dbg(dev, "%s processing: [blob: %p (%zu), mem_type: %x, color: %x,",
|
||||
__func__, blob, info->blob_len, mem_type, color);
|
||||
dev_dbg(dev, " key_mod: %p (%zu), black_key: %p (%zu) real_len: %zu]\n",
|
||||
info->key_mod, info->key_mod_len, info->black_key,
|
||||
info->black_key_len, black_key_real_len);
|
||||
|
||||
/* Map blob, this will be transferred to CAAM */
|
||||
if (mem_type == DATA_GENMEM) {
|
||||
if (map_write_data(dev, blob, info->blob_len,
|
||||
&blob_dma, &tmp_blob)) {
|
||||
dev_err(dev, "Unable to map blob for decap\n");
|
||||
ret = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
} else {
|
||||
blob_dma = get_caam_dma_addr(blob);
|
||||
if (!blob_dma)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Map key modifier, this will be sent to CAAM */
|
||||
if (mem_type == DATA_GENMEM) {
|
||||
if (map_write_data(dev, info->key_mod, info->key_mod_len,
|
||||
&key_mod_dma, &tmp_key_mod)) {
|
||||
dev_err(dev, "Unable to map key_mod for blob decap\n");
|
||||
ret = -ENOMEM;
|
||||
goto unmap_blob;
|
||||
}
|
||||
} else {
|
||||
key_mod_dma = get_caam_dma_addr(info->key_mod);
|
||||
if (!key_mod_dma)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Map black key, this will be read from CAAM */
|
||||
if (mem_type == DATA_GENMEM) {
|
||||
if (map_read_data(dev, info->black_key_len,
|
||||
&black_key_dma, &tmp_black_key)) {
|
||||
dev_err(dev, "Unable to map black key for blob decap\n");
|
||||
ret = -ENOMEM;
|
||||
goto unmap_key_mod;
|
||||
}
|
||||
} else {
|
||||
black_key_dma = get_caam_dma_addr(info->black_key);
|
||||
if (!black_key_dma)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = cnstr_desc_blob_decap(&desc, blob_dma, info->blob_len,
|
||||
key_mod_dma, info->key_mod_len,
|
||||
black_key_dma, black_key_real_len,
|
||||
color, key_enc, trusted_key, mem_type);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"Failed to construct the descriptor for blob decap\n");
|
||||
goto unmap_black_key;
|
||||
}
|
||||
|
||||
ret = caam_jr_run_and_wait_for_completion(dev, desc,
|
||||
caam_key_blob_done);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to execute blob decap descriptor\n");
|
||||
goto free_desc;
|
||||
}
|
||||
|
||||
/* Read black key from CAAM */
|
||||
if (mem_type == DATA_GENMEM)
|
||||
read_map_data(dev, info->black_key, black_key_dma,
|
||||
tmp_black_key, info->black_key_len);
|
||||
|
||||
free_desc:
|
||||
kfree(desc);
|
||||
|
||||
unmap_black_key:
|
||||
if (mem_type == DATA_GENMEM)
|
||||
unmap_read_write_data(dev, black_key_dma, tmp_black_key,
|
||||
info->black_key_len, DMA_FROM_DEVICE);
|
||||
|
||||
unmap_key_mod:
|
||||
if (mem_type == DATA_GENMEM)
|
||||
unmap_read_write_data(dev, key_mod_dma, tmp_key_mod,
|
||||
info->key_mod_len, DMA_TO_DEVICE);
|
||||
|
||||
unmap_blob:
|
||||
if (mem_type == DATA_GENMEM)
|
||||
unmap_read_write_data(dev, blob_dma, tmp_blob,
|
||||
info->blob_len, DMA_TO_DEVICE);
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(caam_blob_decap);
|
77
drivers/crypto/caam/caamkeyblob.h
Normal file
77
drivers/crypto/caam/caamkeyblob.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
|
||||
/*
|
||||
* Black key generation and blob encapsulation/decapsualtion for CAAM
|
||||
*
|
||||
* Copyright 2018-2020 NXP
|
||||
*/
|
||||
|
||||
#ifndef _CAAMKEYBLOB_H_
|
||||
#define _CAAMKEYBLOB_H_
|
||||
|
||||
#include <linux/device.h>
|
||||
#include "caamkeyblob_desc.h"
|
||||
|
||||
/*
|
||||
* Minimum key size to be used is 16 bytes and maximum key size fixed
|
||||
* is 64 bytes.
|
||||
* Blob size to be kept is Maximum key size + blob header added by CAAM.
|
||||
*/
|
||||
|
||||
#define MIN_KEY_SIZE 16
|
||||
#define MAX_KEY_SIZE 64
|
||||
|
||||
#define MAX_BLACK_KEY_SIZE (MAX_KEY_SIZE + CCM_OVERHEAD +\
|
||||
TAG_OVERHEAD_SIZE)
|
||||
|
||||
#define BLOB_HEADER_SIZE 4
|
||||
#define MAX_BLOB_SIZE (MAX_KEY_SIZE + BLOB_OVERHEAD +\
|
||||
BLOB_HEADER_SIZE)
|
||||
|
||||
/* Key modifier for CAAM blobs, used as a revision number */
|
||||
static const char caam_key_modifier[KEYMOD_SIZE_GM] = {
|
||||
'C', 'A', 'A', 'M', '_', 'K', 'E', 'Y',
|
||||
'_', 'T', 'Y', 'P', 'E', '_', 'V', '1',
|
||||
};
|
||||
|
||||
/**
|
||||
* struct keyblob_info - Structure that contains all the data necessary
|
||||
* to generate a black key and encapsulate it into a blob
|
||||
*
|
||||
* @key : The plaintext used as input key
|
||||
* for black key generation
|
||||
* @key_len : Size of plaintext or size of key in case of
|
||||
* black key generated from random
|
||||
* @type : The type of data contained (e.g. black key, blob, etc.)
|
||||
* @black_key_len : Length of the generated black key
|
||||
* @black_key : Black key data obtained from CAAM
|
||||
* @blob_len : Length of the blob that encapsulates the black key
|
||||
* @blob : Blob data obtained from CAAM
|
||||
* @key_modifier_len : 8-byte or 16-byte Key_Modifier based on general or
|
||||
* secure memory blob type
|
||||
* @key_modifier : can be either a secret value, or used as a revision
|
||||
* number, revision date or nonce
|
||||
* In this case is used as a revision number.
|
||||
*/
|
||||
struct keyblob_info {
|
||||
char *key;
|
||||
size_t key_len;
|
||||
|
||||
u32 type;
|
||||
|
||||
size_t black_key_len;
|
||||
unsigned char black_key[MAX_BLACK_KEY_SIZE];
|
||||
|
||||
size_t blob_len;
|
||||
unsigned char blob[MAX_BLOB_SIZE];
|
||||
|
||||
size_t key_mod_len;
|
||||
const void *key_mod;
|
||||
};
|
||||
|
||||
int generate_black_key(struct device *dev, struct keyblob_info *info);
|
||||
|
||||
int caam_blob_encap(struct device *dev, struct keyblob_info *info);
|
||||
|
||||
int caam_blob_decap(struct device *dev, struct keyblob_info *info);
|
||||
|
||||
#endif /* _CAAMKEYBLOB_H_ */
|
455
drivers/crypto/caam/caamkeyblob_desc.c
Normal file
455
drivers/crypto/caam/caamkeyblob_desc.c
Normal file
|
@ -0,0 +1,455 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
||||
/*
|
||||
* Shared descriptors for CAAM black key
|
||||
* and blob encapsulation/decapsulation
|
||||
*
|
||||
* Copyright 2018-2020 NXP
|
||||
*/
|
||||
#include "caamkeyblob_desc.h"
|
||||
|
||||
/* Size of tmp buffer for descriptor const. */
|
||||
#define INITIAL_DESCSZ 16
|
||||
|
||||
/*
|
||||
* Construct a black key conversion job descriptor
|
||||
*
|
||||
* This function constructs a job descriptor capable of performing
|
||||
* a key blackening operation on a plaintext secure memory resident object.
|
||||
*
|
||||
* @desc : Pointer to a pointer to the descriptor generated by this
|
||||
* function. Caller will be responsible to kfree() this
|
||||
* descriptor after execution.
|
||||
* @key : Physical pointer to the plaintext, which will also hold
|
||||
* the result. Since encryption occurs in place, caller must
|
||||
* ensure that the space is large enough to accommodate the
|
||||
* blackened key
|
||||
* @key_len : Size of the plaintext
|
||||
* @black_key : DMA address of the black key obtained from hardware
|
||||
* @black_key_len : Size of the black key
|
||||
* @key_enc : Encrypted Key Type (AES-ECB or AES-CCM)
|
||||
* @trusted_key : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
|
||||
* or Trusted Descriptor Key Encryption Key (TDKEK) to
|
||||
* decrypt the key to be loaded into a Key Register).
|
||||
*
|
||||
* Return : '0' on success, error code otherwise
|
||||
*/
|
||||
int cnstr_desc_black_key(u32 **desc, dma_addr_t key, size_t key_len,
|
||||
dma_addr_t black_key, size_t black_key_len,
|
||||
u8 key_enc, u8 trusted_key)
|
||||
{
|
||||
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
|
||||
u16 dsize, idx;
|
||||
u32 key_length_for_desc = key_len;
|
||||
|
||||
/* Trusted key not supported */
|
||||
if (trusted_key != UNTRUSTED_KEY)
|
||||
return -ENOTSUPP;
|
||||
|
||||
memset(tmpdesc, 0, sizeof(tmpdesc));
|
||||
idx = 1;
|
||||
|
||||
/*
|
||||
* KEY commands seems limited to 32 bytes, so we should use the load
|
||||
* command instead which can load up to 64 bytes.
|
||||
* The size must also be loaded.
|
||||
*
|
||||
* TODO: The KEY command indicate it should be able to load key bigger
|
||||
* than 32bytes but it doesn't work in practice
|
||||
*
|
||||
* TODO: The LOAD command indicate it should be able to load up to 96
|
||||
* byte keys it doesn't work in practice and is limited to 64 bytes
|
||||
*/
|
||||
|
||||
/* Load key to class 1 key register */
|
||||
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_1_CCB | LDST_SRCDST_BYTE_KEY |
|
||||
key_length_for_desc;
|
||||
tmpdesc[idx++] = (uintptr_t)key;
|
||||
/* Load the size of the key */
|
||||
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_1_CCB | LDST_IMM |
|
||||
LDST_SRCDST_WORD_KEYSZ_REG |
|
||||
sizeof(key_length_for_desc);
|
||||
tmpdesc[idx++] = key_length_for_desc;
|
||||
|
||||
/* ...and write back out via FIFO store*/
|
||||
tmpdesc[idx] = CMD_FIFO_STORE | CLASS_1 |
|
||||
(black_key_len & KEY_LENGTH_MASK);
|
||||
|
||||
/* Plus account for ECB/CCM option in FIFO_STORE */
|
||||
if (key_enc == KEY_COVER_ECB)
|
||||
tmpdesc[idx] |= FIFOST_TYPE_KEY_KEK;
|
||||
else
|
||||
tmpdesc[idx] |= FIFOST_TYPE_KEY_CCM_JKEK;
|
||||
|
||||
idx++;
|
||||
tmpdesc[idx++] = (uintptr_t)black_key;
|
||||
|
||||
/* Finish off the job header */
|
||||
tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
|
||||
dsize = desc_bytes(&tmpdesc);
|
||||
|
||||
/* Now allocate execution buffer and coat it with executable */
|
||||
tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
|
||||
if (!tdesc)
|
||||
return -ENOMEM;
|
||||
|
||||
*desc = tdesc;
|
||||
|
||||
print_hex_dump_debug("black key desc@" __stringify(__LINE__) ":",
|
||||
DUMP_PREFIX_ADDRESS, 16, 4, *desc,
|
||||
desc_bytes(*desc), 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cnstr_desc_black_key);
|
||||
|
||||
/*
|
||||
* Construct a black key using RNG job descriptor
|
||||
*
|
||||
* This function constructs a job descriptor capable of performing
|
||||
* a key blackening operation on RNG generated.
|
||||
*
|
||||
* @desc : Pointer to a pointer to the descriptor generated by this
|
||||
* function. Caller will be responsible to kfree() this
|
||||
* descriptor after execution.
|
||||
* @key_len : Size of the random plaintext
|
||||
* @black_key : DMA address of the black key obtained from hardware
|
||||
* @black_key_len : Size of the black key
|
||||
* @key_enc : Encrypted Key Type (AES-ECB or AES-CCM)
|
||||
* @trusted_key : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
|
||||
* or Trusted Descriptor Key Encryption Key (TDKEK) to
|
||||
* decrypt the key to be loaded into a Key Register).
|
||||
*
|
||||
* Return : '0' on success, error code otherwise
|
||||
*/
|
||||
int cnstr_desc_random_black_key(u32 **desc, size_t key_len,
|
||||
dma_addr_t black_key, size_t black_key_len,
|
||||
u8 key_enc, u8 trusted_key)
|
||||
{
|
||||
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
|
||||
u16 dsize;
|
||||
u32 bk_store;
|
||||
|
||||
memset(tmpdesc, 0, sizeof(tmpdesc));
|
||||
|
||||
init_job_desc(tmpdesc, CMD_DESC_HDR);
|
||||
|
||||
/* Prepare RNG */
|
||||
append_operation(tmpdesc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG);
|
||||
|
||||
/* Generate RNG and left it in output data fifo */
|
||||
append_cmd(tmpdesc, CMD_FIFO_STORE | FIFOST_TYPE_RNGFIFO | key_len);
|
||||
|
||||
/* Copy RNG from outfifo to class 1 Key register */
|
||||
append_move(tmpdesc, MOVE_SRC_OUTFIFO | MOVE_DEST_CLASS1KEY |
|
||||
MOVE_WAITCOMP | (key_len & MOVE_LEN_MASK));
|
||||
|
||||
/* Write the size of the key moved */
|
||||
append_load_imm_u32(tmpdesc, key_len, LDST_CLASS_1_CCB |
|
||||
LDST_SRCDST_WORD_KEYSZ_REG | LDST_IMM);
|
||||
|
||||
bk_store = CLASS_1;
|
||||
if (key_enc == KEY_COVER_ECB)
|
||||
bk_store |= FIFOST_TYPE_KEY_KEK;
|
||||
else
|
||||
bk_store |= FIFOST_TYPE_KEY_CCM_JKEK;
|
||||
|
||||
/* Fifo store to save the key as black key in memory */
|
||||
append_fifo_store(tmpdesc, black_key, black_key_len, bk_store);
|
||||
|
||||
dsize = desc_bytes(&tmpdesc);
|
||||
|
||||
/* Now allocate execution buffer and coat it with executable */
|
||||
tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
|
||||
if (!tdesc)
|
||||
return -ENOMEM;
|
||||
|
||||
*desc = tdesc;
|
||||
|
||||
print_hex_dump_debug("black key random desc@" __stringify(__LINE__) ":",
|
||||
DUMP_PREFIX_ADDRESS, 16, 4, *desc,
|
||||
desc_bytes(*desc), 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cnstr_desc_random_black_key);
|
||||
|
||||
/*
|
||||
* Construct a blob encapsulation job descriptor
|
||||
*
|
||||
* This function dynamically constructs a blob encapsulation job descriptor
|
||||
* from the following arguments:
|
||||
*
|
||||
* @desc : Pointer to a pointer to the descriptor generated by this
|
||||
* function. Caller will be responsible to kfree() this
|
||||
* descriptor after execution.
|
||||
* @black_key : Physical pointer to a secret, normally a black or red key,
|
||||
* possibly residing within an accessible secure memory page,
|
||||
* of the secret to be encapsulated to an output blob.
|
||||
* @black_key_len : Size of input secret, in bytes. This is limited to 65536
|
||||
* less the size of blob overhead, since the length embeds
|
||||
* into DECO pointer in/out instructions.
|
||||
* @keycolor : Determines if the source data is covered (black key) or
|
||||
* plaintext (red key). RED_KEY or BLACK_KEY are defined in
|
||||
* for this purpose.
|
||||
* @key_enc : If BLACK_KEY source is covered via AES-CCM, specify
|
||||
* KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB).
|
||||
* @trusted_key : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
|
||||
* or Trusted Descriptor Key Encryption Key (TDKEK) to
|
||||
* decrypt the key to be loaded into a Key Register).
|
||||
* @mem_type : Determine if encapsulated blob should be a secure memory
|
||||
* blob (DATA_SECMEM), with partition data embedded with key
|
||||
* material, or a general memory blob (DATA_GENMEM).
|
||||
* @key_mod : Physical pointer to a key modifier, which must reside in a
|
||||
* contiguous piece of memory. Modifier will be assumed to be
|
||||
* 8 bytes long for a blob of type DATA_SECMEM, or 16 bytes
|
||||
* long for a blob of type DATA_GENMEM
|
||||
* @key_mod_len : Modifier length is 8 bytes long for a blob of type
|
||||
* DATA_SECMEM, or 16 bytes long for a blob of type DATA_GENMEM
|
||||
* @blob : Physical pointer to the destination buffer to receive the
|
||||
* encapsulated output. This buffer will need to be 48 bytes
|
||||
* larger than the input because of the added encapsulation
|
||||
* data. The generated descriptor will account for the
|
||||
* increase in size, but the caller must also account for
|
||||
* this increase in the buffer allocator.
|
||||
* @blob_len : Size of the destination buffer to receive the
|
||||
* encapsulated output.
|
||||
* Return : '0' on success, error code otherwise
|
||||
*
|
||||
* Upon completion, desc points to a buffer containing a CAAM job
|
||||
* descriptor which encapsulates data into an externally-storable blob
|
||||
* suitable for use across power cycles.
|
||||
*
|
||||
* This is an example of a black key encapsulation job into a general memory
|
||||
* blob. Notice the 16-byte key modifier in the LOAD instruction. Also note
|
||||
* the output 48 bytes longer than the input:
|
||||
*
|
||||
* [00] B0800008 jobhdr: stidx=0 len=8
|
||||
* [01] 14400010 ld: ccb2-key len=16 offs=0
|
||||
* [02] 08144891 ptr->@0x08144891
|
||||
* [03] F800003A seqoutptr: len=58
|
||||
* [04] 01000000 out_ptr->@0x01000000
|
||||
* [05] F000000A seqinptr: len=10
|
||||
* [06] 09745090 in_ptr->@0x09745090
|
||||
* [07] 870D0004 operation: encap blob reg=memory, black, format=normal
|
||||
*
|
||||
* This is an example of a red key encapsulation job for storing a red key
|
||||
* into a secure memory blob. Note the 8 byte modifier on the 12 byte offset
|
||||
* in the LOAD instruction; this accounts for blob permission storage:
|
||||
*
|
||||
* [00] B0800008 jobhdr: stidx=0 len=8
|
||||
* [01] 14400C08 ld: ccb2-key len=8 offs=12
|
||||
* [02] 087D0784 ptr->@0x087d0784
|
||||
* [03] F8000050 seqoutptr: len=80
|
||||
* [04] 09251BB2 out_ptr->@0x09251bb2
|
||||
* [05] F0000020 seqinptr: len=32
|
||||
* [06] 40000F31 in_ptr->@0x40000f31
|
||||
* [07] 870D0008 operation: encap blob reg=memory, red, sec_mem,
|
||||
* format=normal
|
||||
*/
|
||||
int cnstr_desc_blob_encap(u32 **desc, dma_addr_t black_key,
|
||||
size_t black_key_len, u8 keycolor, u8 key_enc,
|
||||
u8 trusted_key, u8 mem_type, dma_addr_t key_mod,
|
||||
size_t key_mod_len, dma_addr_t blob, size_t blob_len)
|
||||
{
|
||||
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
|
||||
u16 dsize, idx;
|
||||
|
||||
/* Trusted key not supported */
|
||||
if (trusted_key != UNTRUSTED_KEY)
|
||||
return -ENOTSUPP;
|
||||
|
||||
memset(tmpdesc, 0, sizeof(tmpdesc));
|
||||
idx = 1;
|
||||
|
||||
/*
|
||||
* Key modifier works differently for secure/general memory blobs
|
||||
* This accounts for the permission/protection data encapsulated
|
||||
* within the blob if a secure memory blob is requested
|
||||
*/
|
||||
if (mem_type == DATA_SECMEM)
|
||||
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
|
||||
LDST_SRCDST_BYTE_KEY |
|
||||
((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
|
||||
| (key_mod_len & LDST_LEN_MASK);
|
||||
else /* is general memory blob */
|
||||
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB
|
||||
| LDST_SRCDST_BYTE_KEY
|
||||
| (key_mod_len & LDST_LEN_MASK);
|
||||
|
||||
tmpdesc[idx++] = (u32)key_mod;
|
||||
|
||||
/*
|
||||
* Encapsulation output must include space for blob key encryption
|
||||
* key and MAC tag
|
||||
*/
|
||||
tmpdesc[idx++] = CMD_SEQ_OUT_PTR | (black_key_len + BLOB_OVERHEAD);
|
||||
tmpdesc[idx++] = (u32)blob;
|
||||
|
||||
/* Input data, should be somewhere in secure memory */
|
||||
tmpdesc[idx++] = CMD_SEQ_IN_PTR | black_key_len;
|
||||
tmpdesc[idx++] = (uintptr_t)black_key;
|
||||
|
||||
/* Set blob encap, then color */
|
||||
tmpdesc[idx] = CMD_OPERATION | OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB;
|
||||
|
||||
if (mem_type == DATA_SECMEM)
|
||||
tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
|
||||
|
||||
if (key_enc == KEY_COVER_CCM)
|
||||
tmpdesc[idx] |= OP_PCL_BLOB_EKT;
|
||||
|
||||
/* An input black key cannot be stored in a red blob */
|
||||
if (keycolor == BLACK_KEY)
|
||||
tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
|
||||
|
||||
idx++;
|
||||
tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
|
||||
dsize = desc_bytes(&tmpdesc);
|
||||
|
||||
tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
|
||||
if (!tdesc)
|
||||
return -ENOMEM;
|
||||
|
||||
*desc = tdesc;
|
||||
|
||||
print_hex_dump_debug("blob encap desc@" __stringify(__LINE__) ":",
|
||||
DUMP_PREFIX_ADDRESS, 16, 4, *desc,
|
||||
desc_bytes(*desc), 1);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cnstr_desc_blob_encap);
|
||||
|
||||
/*
|
||||
* Construct a blob decapsulation job descriptor
|
||||
*
|
||||
* This function dynamically constructs a blob decapsulation job descriptor
|
||||
* from the following arguments:
|
||||
*
|
||||
* @desc : Pointer to a pointer to the descriptor generated by this
|
||||
* function. Caller will be responsible to kfree() this
|
||||
* descriptor after execution.
|
||||
* @blob : Physical pointer (into external memory) of the blob to
|
||||
* be decapsulated. Blob must reside in a contiguous memory
|
||||
* segment.
|
||||
* @blob_len : Size of the blob buffer to be decapsulated.
|
||||
* @key_mod : Physical pointer to a key modifier, which must reside in a
|
||||
* contiguous piece of memory. Modifier will be assumed to be
|
||||
* 8 bytes long for a blob of type DATA_SECMEM, or 16 bytes
|
||||
* long for a blob of type DATA_GENMEM
|
||||
* @key_mod_len : Modifier length is 8 bytes long for a blob of type
|
||||
* DATA_SECMEM, or 16 bytes long for a blob of type DATA_GENMEM
|
||||
* @black_key : Physical pointer of the decapsulated output, possibly into
|
||||
* a location within a secure memory page. Must be contiguous.
|
||||
* @black_key_len : Size of encapsulated secret in bytes (not the size of the
|
||||
* input blob).
|
||||
* @keycolor : Determines if the source data is covered (black key) or
|
||||
* plaintext (red key). RED_KEY or BLACK_KEY are defined in
|
||||
* for this purpose.
|
||||
* @key_enc : If BLACK_KEY source is covered via AES-CCM, specify
|
||||
* KEY_COVER_CCM, else uses AES-ECB (KEY_COVER_ECB).
|
||||
* @trusted_key : Trusted Key (use Job Descriptor Key Encryption Key (JDKEK)
|
||||
* or Trusted Descriptor Key Encryption Key (TDKEK) to
|
||||
* decrypt the key to be loaded into a Key Register).
|
||||
* @mem_type : Determine if encapsulated blob should be a secure memory
|
||||
* blob (DATA_SECMEM), with partition data embedded with key
|
||||
* material, or a general memory blob (DATA_GENMEM).
|
||||
* Return : '0' on success, error code otherwise
|
||||
*
|
||||
* Upon completion, desc points to a buffer containing a CAAM job descriptor
|
||||
* that decapsulates a key blob from external memory into a black (encrypted)
|
||||
* key or red (plaintext) content.
|
||||
*
|
||||
* This is an example of a black key decapsulation job from a general memory
|
||||
* blob. Notice the 16-byte key modifier in the LOAD instruction.
|
||||
*
|
||||
* [00] B0800008 jobhdr: stidx=0 len=8
|
||||
* [01] 14400010 ld: ccb2-key len=16 offs=0
|
||||
* [02] 08A63B7F ptr->@0x08a63b7f
|
||||
* [03] F8000010 seqoutptr: len=16
|
||||
* [04] 01000000 out_ptr->@0x01000000
|
||||
* [05] F000003A seqinptr: len=58
|
||||
* [06] 01000010 in_ptr->@0x01000010
|
||||
* [07] 860D0004 operation: decap blob reg=memory, black, format=normal
|
||||
*
|
||||
* This is an example of a red key decapsulation job for restoring a red key
|
||||
* from a secure memory blob. Note the 8 byte modifier on the 12 byte offset
|
||||
* in the LOAD instruction:
|
||||
*
|
||||
* [00] B0800008 jobhdr: stidx=0 len=8
|
||||
* [01] 14400C08 ld: ccb2-key len=8 offs=12
|
||||
* [02] 01000000 ptr->@0x01000000
|
||||
* [03] F8000020 seqoutptr: len=32
|
||||
* [04] 400000E6 out_ptr->@0x400000e6
|
||||
* [05] F0000050 seqinptr: len=80
|
||||
* [06] 08F0C0EA in_ptr->@0x08f0c0ea
|
||||
* [07] 860D0008 operation: decap blob reg=memory, red, sec_mem,
|
||||
* format=normal
|
||||
*/
|
||||
int cnstr_desc_blob_decap(u32 **desc, dma_addr_t blob, size_t blob_len,
|
||||
dma_addr_t key_mod, size_t key_mod_len,
|
||||
dma_addr_t black_key, size_t black_key_len,
|
||||
u8 keycolor, u8 key_enc, u8 trusted_key, u8 mem_type)
|
||||
{
|
||||
u32 *tdesc, tmpdesc[INITIAL_DESCSZ];
|
||||
u16 dsize, idx;
|
||||
|
||||
/* Trusted key not supported */
|
||||
if (trusted_key != UNTRUSTED_KEY)
|
||||
return -ENOTSUPP;
|
||||
|
||||
memset(tmpdesc, 0, sizeof(tmpdesc));
|
||||
idx = 1;
|
||||
|
||||
/* Load key modifier */
|
||||
if (mem_type == DATA_SECMEM)
|
||||
tmpdesc[idx++] = CMD_LOAD | LDST_CLASS_2_CCB |
|
||||
LDST_SRCDST_BYTE_KEY |
|
||||
((12 << LDST_OFFSET_SHIFT) & LDST_OFFSET_MASK)
|
||||
| (key_mod_len & LDST_LEN_MASK);
|
||||
else /* is general memory blob */
|
||||
tmpdesc[idx++] = CMD_LOAD
|
||||
| LDST_CLASS_2_CCB
|
||||
| LDST_SRCDST_BYTE_KEY
|
||||
| (key_mod_len & LDST_LEN_MASK);
|
||||
|
||||
tmpdesc[idx++] = (u32)key_mod;
|
||||
|
||||
/* Compensate BKEK + MAC tag over size of encapsulated secret */
|
||||
tmpdesc[idx++] = CMD_SEQ_IN_PTR | blob_len;
|
||||
tmpdesc[idx++] = (u32)blob;
|
||||
tmpdesc[idx++] = CMD_SEQ_OUT_PTR | black_key_len;
|
||||
tmpdesc[idx++] = (uintptr_t)black_key;
|
||||
|
||||
/* Decapsulate from secure memory partition to black blob */
|
||||
tmpdesc[idx] = CMD_OPERATION | OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB;
|
||||
|
||||
if (mem_type == DATA_SECMEM)
|
||||
tmpdesc[idx] |= OP_PCL_BLOB_PTXT_SECMEM;
|
||||
|
||||
if (key_enc == KEY_COVER_CCM)
|
||||
tmpdesc[idx] |= OP_PCL_BLOB_EKT;
|
||||
|
||||
if (keycolor == BLACK_KEY)
|
||||
tmpdesc[idx] |= OP_PCL_BLOB_BLACK;
|
||||
|
||||
idx++;
|
||||
tmpdesc[0] = CMD_DESC_HDR | HDR_ONE | (idx & HDR_DESCLEN_MASK);
|
||||
dsize = desc_bytes(&tmpdesc);
|
||||
|
||||
tdesc = kmemdup(tmpdesc, dsize, GFP_KERNEL | GFP_DMA);
|
||||
if (!tdesc)
|
||||
return -ENOMEM;
|
||||
|
||||
*desc = tdesc;
|
||||
|
||||
print_hex_dump_debug("blob decap desc@" __stringify(__LINE__) ":",
|
||||
DUMP_PREFIX_ADDRESS, 16, 4, *desc,
|
||||
desc_bytes(*desc), 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(cnstr_desc_blob_decap);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("NXP CAAM Black Key and Blob descriptors");
|
||||
MODULE_AUTHOR("NXP Semiconductors");
|
101
drivers/crypto/caam/caamkeyblob_desc.h
Normal file
101
drivers/crypto/caam/caamkeyblob_desc.h
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */
|
||||
/*
|
||||
* Shared descriptors for CAAM black key and blob
|
||||
*
|
||||
* Copyright 2018-2020 NXP
|
||||
*/
|
||||
|
||||
#ifndef _CAAMKEYBLOB_DESC_H_
|
||||
#define _CAAMKEYBLOB_DESC_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "jr.h"
|
||||
#include "regs.h"
|
||||
#include "desc.h"
|
||||
|
||||
#include "compat.h"
|
||||
#include "tag_object.h"
|
||||
#include "desc_constr.h"
|
||||
|
||||
/* Defines for secure memory and general memory blobs */
|
||||
#define DATA_GENMEM 0
|
||||
#define DATA_SECMEM 1
|
||||
|
||||
/* Encrypted key */
|
||||
#define BLACK_KEY 1
|
||||
|
||||
/* Define key encryption/covering options */
|
||||
#define KEY_COVER_ECB 0 /* cover key in AES-ECB */
|
||||
#define KEY_COVER_CCM 1 /* cover key with AES-CCM */
|
||||
|
||||
/* Define the trust in the key, to select either JDKEK or TDKEK */
|
||||
#define UNTRUSTED_KEY 0
|
||||
#define TRUSTED_KEY 1
|
||||
|
||||
/* Define space required for BKEK + MAC tag storage in any blob */
|
||||
#define BLOB_OVERHEAD (32 + 16)
|
||||
|
||||
#define PAD_16_BYTE(_key_size) (roundup(_key_size, 16))
|
||||
#define PAD_8_BYTE(_key_size) (roundup(_key_size, 8))
|
||||
|
||||
/*
|
||||
* ECB-Black Key will be padded with zeros to make it a
|
||||
* multiple of 16 bytes long before it is encrypted,
|
||||
* and the resulting Black Key will be this length.
|
||||
*/
|
||||
#define ECB_BLACK_KEY_SIZE(_key_size) (PAD_16_BYTE(_key_size))
|
||||
|
||||
/*
|
||||
* CCM-Black Key will always be at least 12 bytes longer,
|
||||
* since the encapsulation uses a 6-byte nonce and adds
|
||||
* a 6-byte ICV. But first, the key is padded as necessary so
|
||||
* that CCM-Black Key is a multiple of 8 bytes long.
|
||||
*/
|
||||
#define NONCE_SIZE 6
|
||||
#define ICV_SIZE 6
|
||||
#define CCM_OVERHEAD (NONCE_SIZE + ICV_SIZE)
|
||||
#define CCM_BLACK_KEY_SIZE(_key_size) (PAD_8_BYTE(_key_size) \
|
||||
+ CCM_OVERHEAD)
|
||||
|
||||
static inline int secret_size_in_ccm_black_key(int key_size)
|
||||
{
|
||||
return ((key_size >= CCM_OVERHEAD) ? key_size - CCM_OVERHEAD : 0);
|
||||
}
|
||||
|
||||
#define SECRET_SIZE_IN_CCM_BLACK_KEY(_key_size) \
|
||||
secret_size_in_ccm_black_key(_key_size)
|
||||
|
||||
/* A red key is not encrypted so its size is the same */
|
||||
#define RED_KEY_SIZE(_key_size) (_key_size)
|
||||
|
||||
/*
|
||||
* Based on memory type, the key modifier length
|
||||
* can be either 8-byte or 16-byte.
|
||||
*/
|
||||
#define KEYMOD_SIZE_SM 8
|
||||
#define KEYMOD_SIZE_GM 16
|
||||
|
||||
/* Create job descriptor to cover key */
|
||||
int cnstr_desc_black_key(u32 **desc, dma_addr_t key, size_t key_len,
|
||||
dma_addr_t black_key, size_t black_key_len,
|
||||
u8 key_enc, u8 trusted_key);
|
||||
|
||||
/* Create job descriptor to generate a random key and cover it */
|
||||
int cnstr_desc_random_black_key(u32 **desc, size_t key_len,
|
||||
dma_addr_t black_key, size_t black_key_len,
|
||||
u8 key_enc, u8 trusted_key);
|
||||
|
||||
/* Encapsulate data in a blob */
|
||||
int cnstr_desc_blob_encap(u32 **desc, dma_addr_t black_key,
|
||||
size_t black_key_len, u8 color, u8 key_enc,
|
||||
u8 trusted_key, u8 mem_type, dma_addr_t key_mod,
|
||||
size_t key_mod_len, dma_addr_t blob, size_t blob_len);
|
||||
|
||||
/* Decapsulate data from a blob */
|
||||
int cnstr_desc_blob_decap(u32 **desc, dma_addr_t blob, size_t blob_len,
|
||||
dma_addr_t key_mod, size_t key_mod_len,
|
||||
dma_addr_t black_key, size_t black_key_len,
|
||||
u8 keycolor, u8 key_enc, u8 trusted_key, u8 mem_type);
|
||||
|
||||
#endif /* _CAAMKEYBLOB_DESC_H_ */
|
127
drivers/crypto/caam/caamkeyblob_test.c
Normal file
127
drivers/crypto/caam/caamkeyblob_test.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
|
||||
/*
|
||||
* Copyright 2018-2020 NXP
|
||||
*
|
||||
* Test of black key generation from a plaintext (of different size)
|
||||
* and from random.
|
||||
* The random black key is encapsulated into a blob.
|
||||
* Next, the blob is decapsulated and the new obtained black key is
|
||||
* compared to the random black key.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include "caamkeyblob.h"
|
||||
|
||||
#define MAX_INPUT_SIZE 64
|
||||
#define KEY_ENCRYPTION_ECB 1
|
||||
#define KEY_ENCRYPTION_CCM 9
|
||||
|
||||
static char input[MAX_INPUT_SIZE];
|
||||
|
||||
static int create_black_key(struct device *dev, struct keyblob_info *info)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = generate_black_key(dev, info);
|
||||
if (ret)
|
||||
dev_err(dev, "black key of size: %zd, type: %d returned %d",
|
||||
info->key_len, info->type, ret);
|
||||
|
||||
return (ret) ? 1 : 0;
|
||||
}
|
||||
|
||||
static int black_key_test(void)
|
||||
{
|
||||
struct device *dev;
|
||||
struct keyblob_info *info;
|
||||
int i, ret = 0, nb_errors = 0;
|
||||
unsigned char tmp_black_key[MAX_BLACK_KEY_SIZE];
|
||||
size_t tmp_black_key_len = 0;
|
||||
|
||||
dev = caam_jr_alloc();
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->key = input;
|
||||
|
||||
for (i = 1; i <= MAX_INPUT_SIZE; i++) {
|
||||
info->key_len = i;
|
||||
|
||||
/* Create a black key encrypted with AES-ECB */
|
||||
info->type = KEY_ENCRYPTION_ECB;
|
||||
info->black_key_len = MAX_INPUT_SIZE;
|
||||
nb_errors += create_black_key(dev, info);
|
||||
|
||||
/* Create a black key encrypted with AES-CCM */
|
||||
info->type = KEY_ENCRYPTION_CCM;
|
||||
info->black_key_len = MAX_INPUT_SIZE + CCM_OVERHEAD;
|
||||
nb_errors += create_black_key(dev, info);
|
||||
}
|
||||
|
||||
/* Create, from random, a black key encrypted with AES-ECB */
|
||||
info->key = NULL;
|
||||
info->type = KEY_ENCRYPTION_ECB;
|
||||
info->black_key_len = MAX_INPUT_SIZE;
|
||||
ret = create_black_key(dev, info);
|
||||
nb_errors += (ret) ? 1 : 0;
|
||||
|
||||
/* Save it for later to compare it */
|
||||
tmp_black_key_len = info->black_key_len;
|
||||
memcpy(tmp_black_key, info->black_key, tmp_black_key_len);
|
||||
|
||||
/* Encapsulate the random black key into a black blob */
|
||||
info->key = NULL;
|
||||
/* Set key modifier, used as revision number, for blob */
|
||||
info->key_mod = caam_key_modifier;
|
||||
info->key_mod_len = ARRAY_SIZE(caam_key_modifier);
|
||||
/* Black key, encrypted with ECB-AES, in General Memory */
|
||||
info->type = KEY_ENCRYPTION_ECB;
|
||||
info->key_len = MAX_INPUT_SIZE;
|
||||
info->blob_len = MAX_BLOB_SIZE;
|
||||
ret = caam_blob_encap(dev, info);
|
||||
nb_errors += (ret) ? 1 : 0;
|
||||
|
||||
/* Decapsulate the black key from the above black blob */
|
||||
ret = caam_blob_decap(dev, info);
|
||||
nb_errors += (ret) ? 1 : 0;
|
||||
|
||||
/*
|
||||
* Compare the generated black key with
|
||||
* the one decapsulated from the blob
|
||||
*/
|
||||
if (info->black_key_len == tmp_black_key_len)
|
||||
ret = memcmp(tmp_black_key, info->black_key, tmp_black_key_len);
|
||||
else
|
||||
ret = 1;
|
||||
nb_errors += ret;
|
||||
|
||||
/*
|
||||
* Check number of errors.
|
||||
* If nb_errors > 0, at least one operation failed, success otherwise
|
||||
*/
|
||||
pr_info("Nb errors: %d\n", nb_errors);
|
||||
|
||||
caam_jr_free(dev);
|
||||
kfree(info);
|
||||
|
||||
return nb_errors;
|
||||
}
|
||||
|
||||
static int black_key_test_init(void)
|
||||
{
|
||||
return black_key_test();
|
||||
}
|
||||
|
||||
static void black_key_test_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(black_key_test_init);
|
||||
module_exit(black_key_test_exit);
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("NXP CAAM Black Key and Blob Test");
|
||||
MODULE_AUTHOR("NXP Semiconductors");
|
|
@ -4,7 +4,7 @@
|
|||
* JobR backend functionality
|
||||
*
|
||||
* Copyright 2008-2012 Freescale Semiconductor, Inc.
|
||||
* Copyright 2019 NXP
|
||||
* Copyright 2019-2020 NXP
|
||||
*/
|
||||
|
||||
#include <linux/of_irq.h>
|
||||
|
@ -534,6 +534,57 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
|
|||
}
|
||||
EXPORT_SYMBOL(caam_jr_enqueue);
|
||||
|
||||
/**
|
||||
* caam_jr_run_and_wait_for_completion() - Enqueue a job and wait for its
|
||||
* completion. Returns 0 if OK, -ENOSPC if the queue is full,
|
||||
* -EIO if it cannot map the caller's descriptor.
|
||||
* @dev: struct device of the job ring to be used
|
||||
* @desc: points to a job descriptor that execute our request. All
|
||||
* descriptors (and all referenced data) must be in a DMAable
|
||||
* region, and all data references must be physical addresses
|
||||
* accessible to CAAM (i.e. within a PAMU window granted
|
||||
* to it).
|
||||
* @cbk: pointer to a callback function to be invoked upon completion
|
||||
* of this request. This has the form:
|
||||
* callback(struct device *dev, u32 *desc, u32 stat, void *arg)
|
||||
* where:
|
||||
* @dev: contains the job ring device that processed this
|
||||
* response.
|
||||
* @desc: descriptor that initiated the request, same as
|
||||
* "desc" being argued to caam_jr_enqueue().
|
||||
* @status: untranslated status received from CAAM. See the
|
||||
* reference manual for a detailed description of
|
||||
* error meaning, or see the JRSTA definitions in the
|
||||
* register header file
|
||||
* @areq: optional pointer to an argument passed with the
|
||||
* original request
|
||||
**/
|
||||
int caam_jr_run_and_wait_for_completion(struct device *dev, u32 *desc,
|
||||
void (*cbk)(struct device *dev,
|
||||
u32 *desc, u32 status,
|
||||
void *areq))
|
||||
{
|
||||
int ret = 0;
|
||||
struct jr_job_result jobres = {0};
|
||||
|
||||
/* Initialize the completion structure */
|
||||
init_completion(&jobres.completion);
|
||||
|
||||
/* Enqueue job for execution */
|
||||
ret = caam_jr_enqueue(dev, desc, cbk, &jobres);
|
||||
if (ret != -EINPROGRESS)
|
||||
return ret;
|
||||
|
||||
/* Wait for job completion */
|
||||
wait_for_completion(&jobres.completion);
|
||||
|
||||
/* Get return code processed in cbk */
|
||||
ret = jobres.error;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(caam_jr_run_and_wait_for_completion);
|
||||
|
||||
static void caam_jr_init_hw(struct device *dev, dma_addr_t inpbusaddr,
|
||||
dma_addr_t outbusaddr)
|
||||
{
|
||||
|
|
|
@ -3,11 +3,26 @@
|
|||
* CAAM public-level include definitions for the JobR backend
|
||||
*
|
||||
* Copyright 2008-2011 Freescale Semiconductor, Inc.
|
||||
* Copyright 2020 NXP
|
||||
*/
|
||||
|
||||
#ifndef JR_H
|
||||
#define JR_H
|
||||
|
||||
#include <linux/completion.h>
|
||||
|
||||
/**
|
||||
* struct jr_job_result - Job Ring result structure, used for requests
|
||||
* that need to run and wait for their completion
|
||||
*
|
||||
* @error : The result returned after request was executed
|
||||
* @completion : Structure used to maintain state for a "completion"
|
||||
*/
|
||||
struct jr_job_result {
|
||||
int error;
|
||||
struct completion completion;
|
||||
};
|
||||
|
||||
/* Prototypes for backend-level services exposed to APIs */
|
||||
int caam_jr_driver_probed(void);
|
||||
struct device *caam_jr_alloc(void);
|
||||
|
@ -17,5 +32,9 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
|
|||
void (*cbk)(struct device *dev, u32 *desc, u32 status,
|
||||
void *areq),
|
||||
void *areq);
|
||||
int caam_jr_run_and_wait_for_completion(struct device *dev, u32 *desc,
|
||||
void (*cbk)(struct device *dev,
|
||||
u32 *desc, u32 status,
|
||||
void *areq));
|
||||
|
||||
#endif /* JR_H */
|
||||
|
|
Loading…
Reference in New Issue
Block a user