1
0
Fork 0
alistair23-linux/security/keys/securekey_desc.c

609 lines
16 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 NXP
*
*/
#include <keys/secure-type.h>
#include "securekey_desc.h"
/* key modifier for blob encapsulation & decapsulation descriptor */
u8 key_modifier[] = "SECURE_KEY";
u32 key_modifier_len = 10;
void caam_sk_rng_desc(struct sk_req *skreq, struct sk_desc *skdesc)
{
struct sk_fetch_rnd_data *fetch_rnd_data = NULL;
struct random_desc *rnd_desc = NULL;
size_t len = 0;
u32 *desc = skreq->hwdesc;
init_job_desc(desc, 0);
fetch_rnd_data = &skreq->req_u.sk_fetch_rnd_data;
rnd_desc = &skdesc->dma_u.random_descp;
len = fetch_rnd_data->key_len;
/* command 0x82500000 */
append_cmd(desc, CMD_OPERATION | OP_TYPE_CLASS1_ALG |
OP_ALG_ALGSEL_RNG);
/* command 0x60340000 | len */
append_cmd(desc, CMD_FIFO_STORE | FIFOST_TYPE_RNGSTORE | len);
append_ptr(desc, rnd_desc->rnd_data);
}
void caam_sk_redblob_encap_desc(struct sk_req *skreq, struct sk_desc *skdesc)
{
struct redblob_encap_desc *red_blob_desc =
&skdesc->dma_u.redblob_encapdesc;
struct sk_red_blob_encap *red_blob_req =
&skreq->req_u.sk_red_blob_encap;
u32 *desc = skreq->hwdesc;
init_job_desc(desc, 0);
/* Load class 2 key with key modifier. */
append_key_as_imm(desc, key_modifier, key_modifier_len,
key_modifier_len, CLASS_2 | KEY_DEST_CLASS_REG);
/* SEQ IN PTR Command. */
append_seq_in_ptr(desc, red_blob_desc->in_data, red_blob_req->data_sz,
0);
/* SEQ OUT PTR Command. */
append_seq_out_ptr(desc, red_blob_desc->redblob,
red_blob_req->redblob_sz, 0);
/* RedBlob encapsulation PROTOCOL Command. */
append_operation(desc, OP_TYPE_ENCAP_PROTOCOL | OP_PCLID_BLOB);
}
/* void caam_sk_redblob_decap_desc(struct sk_req *skreq, struct sk_desc *skdesc)
* brief CAAM Descriptor creator from redblob to plaindata.
* param[in] skreq Pointer to secure key request structure
* param[in] skdesc Pointer to secure key descriptor structure
*/
void caam_sk_redblob_decap_desc(struct sk_req *skreq, struct sk_desc *skdesc)
{
struct redblob_decap_desc *red_blob_desc =
&skdesc->dma_u.redblob_decapdesc;
struct sk_red_blob_decap *red_blob_req =
&skreq->req_u.sk_red_blob_decap;
u32 *desc = skreq->hwdesc;
init_job_desc(desc, 0);
/* Load class 2 key with key modifier. */
append_key_as_imm(desc, key_modifier, key_modifier_len,
key_modifier_len, CLASS_2 | KEY_DEST_CLASS_REG);
/* SEQ IN PTR Command. */
append_seq_in_ptr(desc, red_blob_desc->redblob,
red_blob_req->redblob_sz, 0);
/* SEQ OUT PTR Command. */
append_seq_out_ptr(desc, red_blob_desc->out_data,
red_blob_req->data_sz, 0);
/* RedBlob decapsulation PROTOCOL Command. */
append_operation(desc, OP_TYPE_DECAP_PROTOCOL | OP_PCLID_BLOB);
}
/* int caam_sk_get_random_map(struct device *dev, struct sk_req *req,
* struct sk_desc *skdesc)
* brief DMA map the buffer virtual pointers to physical address.
* param[in] dev Pointer to job ring device structure
* param[in] req Pointer to secure key request structure
* param[in] skdesc Pointer to secure key descriptor structure
* return 0 on success, error value otherwise.
*/
int caam_sk_get_random_map(struct device *dev, struct sk_req *req,
struct sk_desc *skdesc)
{
struct sk_fetch_rnd_data *fetch_rnd_data;
struct random_desc *rnd_desc;
fetch_rnd_data = &req->req_u.sk_fetch_rnd_data;
rnd_desc = &skdesc->dma_u.random_descp;
rnd_desc->rnd_data = dma_map_single(dev, fetch_rnd_data->data,
fetch_rnd_data->key_len, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, rnd_desc->rnd_data)) {
dev_err(dev, "Unable to map memory\n");
goto sk_random_map_fail;
}
return 0;
sk_random_map_fail:
return -ENOMEM;
}
/* int caam_sk_redblob_encap_map(struct device *dev, struct sk_req *req,
* struct sk_desc *skdesc)
* brief DMA map the buffer virtual pointers to physical address.
* param[in] dev Pointer to job ring device structure
* param[in] req Pointer to secure key request structure
* param[in] skdesc Pointer to secure key descriptor structure
* return 0 on success, error value otherwise.
*/
int caam_sk_redblob_encap_map(struct device *dev, struct sk_req *req,
struct sk_desc *skdesc)
{
struct sk_red_blob_encap *red_blob_encap;
struct redblob_encap_desc *red_blob_desc;
red_blob_encap = &req->req_u.sk_red_blob_encap;
red_blob_desc = &skdesc->dma_u.redblob_encapdesc;
red_blob_desc->in_data = dma_map_single(dev, red_blob_encap->data,
red_blob_encap->data_sz, DMA_TO_DEVICE);
if (dma_mapping_error(dev, red_blob_desc->in_data)) {
dev_err(dev, "Unable to map memory\n");
goto sk_data_fail;
}
red_blob_desc->redblob = dma_map_single(dev, red_blob_encap->redblob,
red_blob_encap->redblob_sz, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, red_blob_desc->redblob)) {
dev_err(dev, "Unable to map memory\n");
goto sk_redblob_fail;
}
return 0;
sk_redblob_fail:
dma_unmap_single(dev, red_blob_desc->in_data, red_blob_encap->data_sz,
DMA_TO_DEVICE);
sk_data_fail:
return -ENOMEM;
}
/* static int caam_sk_redblob_decap_map(struct device *dev,
* struct sk_req *req,
* struct sk_desc *skdesc)
* brief DMA map the buffer virtual pointers to physical address.
* param[in] dev Pointer to job ring device structure
* param[in] req Pointer to secure key request structure
* param[in] skdesc Pointer to secure key descriptor structure
* return 0 on success, error value otherwise.
*/
int caam_sk_redblob_decap_map(struct device *dev, struct sk_req *req,
struct sk_desc *skdesc)
{
struct sk_red_blob_decap *red_blob_decap;
struct redblob_decap_desc *red_blob_desc;
red_blob_decap = &req->req_u.sk_red_blob_decap;
red_blob_desc = &skdesc->dma_u.redblob_decapdesc;
red_blob_desc->redblob = dma_map_single(dev, red_blob_decap->redblob,
red_blob_decap->redblob_sz, DMA_TO_DEVICE);
if (dma_mapping_error(dev, red_blob_desc->redblob)) {
dev_err(dev, "Unable to map memory\n");
goto sk_redblob_fail;
}
red_blob_desc->out_data = dma_map_single(dev, red_blob_decap->data,
red_blob_decap->data_sz, DMA_FROM_DEVICE);
if (dma_mapping_error(dev, red_blob_desc->out_data)) {
dev_err(dev, "Unable to map memory\n");
goto sk_data_fail;
}
return 0;
sk_data_fail:
dma_unmap_single(dev, red_blob_desc->redblob,
red_blob_decap->redblob_sz, DMA_TO_DEVICE);
sk_redblob_fail:
return -ENOMEM;
}
/* @fn void securekey_unmap(struct device *dev,
* struct sk_desc *skdesc, struct sk_req *req)
* @brief DMA unmap the buffer pointers.
* @param[in] dev Pointer to job ring device structure
* @param[in] skdesc Pointer to secure key descriptor structure
* @param[in] req Pointer to secure key request structure
*/
void securekey_unmap(struct device *dev,
struct sk_desc *skdesc, struct sk_req *req)
{
switch (req->type) {
case sk_get_random:
{
struct sk_fetch_rnd_data *fetch_rnd_data;
struct random_desc *rnd_desc;
fetch_rnd_data = &req->req_u.sk_fetch_rnd_data;
rnd_desc = &skdesc->dma_u.random_descp;
/* Unmap Descriptor buffer pointers. */
dma_unmap_single(dev, rnd_desc->rnd_data,
fetch_rnd_data->key_len,
DMA_FROM_DEVICE);
break;
}
case sk_red_blob_enc:
{
struct sk_red_blob_encap *red_blob_encap;
struct redblob_encap_desc *red_blob_desc;
red_blob_encap = &req->req_u.sk_red_blob_encap;
red_blob_desc = &skdesc->dma_u.redblob_encapdesc;
/* Unmap Descriptor buffer pointers. */
dma_unmap_single(dev, red_blob_desc->in_data,
red_blob_encap->data_sz,
DMA_TO_DEVICE);
dma_unmap_single(dev, red_blob_desc->redblob,
red_blob_encap->redblob_sz,
DMA_FROM_DEVICE);
break;
}
case sk_red_blob_dec:
{
struct sk_red_blob_decap *red_blob_decap;
struct redblob_decap_desc *red_blob_desc;
red_blob_decap = &req->req_u.sk_red_blob_decap;
red_blob_desc = &skdesc->dma_u.redblob_decapdesc;
/* Unmap Descriptor buffer pointers. */
dma_unmap_single(dev, red_blob_desc->redblob,
red_blob_decap->redblob_sz,
DMA_TO_DEVICE);
dma_unmap_single(dev, red_blob_desc->out_data,
red_blob_decap->data_sz,
DMA_FROM_DEVICE);
break;
}
default:
dev_err(dev, "Unable to find request type\n");
break;
}
kfree(skdesc);
}
/* int caam_securekey_desc_init(struct device *dev, struct sk_req *req)
* brief CAAM Descriptor creator for secure key operations.
* param[in] dev Pointer to job ring device structure
* param[in] req Pointer to secure key request structure
* return 0 on success, error value otherwise.
*/
int caam_securekey_desc_init(struct device *dev, struct sk_req *req)
{
struct sk_desc *skdesc = NULL;
int ret = 0;
switch (req->type) {
case sk_get_random:
{
skdesc = kmalloc(sizeof(*skdesc), GFP_DMA);
if (!skdesc) {
ret = -ENOMEM;
goto out;
}
skdesc->req_type = req->type;
if (caam_sk_get_random_map(dev, req, skdesc)) {
dev_err(dev, "caam get_random map fail\n");
ret = -ENOMEM;
goto out;
}
caam_sk_rng_desc(req, skdesc);
break;
}
case sk_red_blob_enc:
{
skdesc = kmalloc(sizeof(*skdesc), GFP_DMA);
if (!skdesc) {
ret = -ENOMEM;
goto out;
}
skdesc->req_type = req->type;
if (caam_sk_redblob_encap_map(dev, req, skdesc)) {
dev_err(dev, "caam redblob_encap map fail\n");
ret = -ENOMEM;
goto out;
}
/* Descriptor function to create redblob from data. */
caam_sk_redblob_encap_desc(req, skdesc);
break;
}
case sk_red_blob_dec:
{
skdesc = kmalloc(sizeof(*skdesc), GFP_DMA);
if (!skdesc) {
ret = -ENOMEM;
goto out;
}
skdesc->req_type = req->type;
if (caam_sk_redblob_decap_map(dev, req, skdesc)) {
dev_err(dev, "caam redblob_decap map fail\n");
ret = -ENOMEM;
goto out;
}
/* Descriptor function to decap data from redblob. */
caam_sk_redblob_decap_desc(req, skdesc);
break;
}
default:
pr_debug("Unknown request type\n");
ret = -EINVAL;
goto out;
}
req->desc_pointer = (void *)skdesc;
out:
return ret;
}
/* static void caam_op_done (struct device *dev, u32 *desc, u32 ret,
* void *context)
* brief callback function to be called when descriptor executed.
* param[in] dev Pointer to device structure
* param[in] desc descriptor pointer
* param[in] ret return status of Job submitted
* param[in] context void pointer
*/
static void caam_op_done(struct device *dev, u32 *desc, u32 ret,
void *context)
{
struct sk_req *req = context;
if (ret) {
dev_err(dev, "caam op done err: %x\n", ret);
/* print the error source name. */
caam_jr_strstatus(dev, ret);
}
/* Call securekey_unmap function for unmapping the buffer pointers. */
securekey_unmap(dev, req->desc_pointer, req);
req->ret = ret;
complete(&req->comp);
}
/* static int sk_job_submit(struct device *jrdev, struct sk_req *req)
* brief Enqueue a Job descriptor to Job ring and wait until SEC returns.
* param[in] jrdev Pointer to job ring device structure
* param[in] req Pointer to secure key request structure
* return 0 on success, error value otherwise.
*/
static int sk_job_submit(struct device *jrdev, struct sk_req *req)
{
int ret;
init_completion(&req->comp);
/* caam_jr_enqueue function for Enqueue a job descriptor */
ret = caam_jr_enqueue(jrdev, req->hwdesc, caam_op_done, req);
if (!ret)
wait_for_completion_interruptible(&req->comp);
ret = req->ret;
return ret;
}
/* caam_get_random(struct secure_key_payload *p, enum sk_req_type fetch_rnd,
* struct device *dev)
* Create the random number of the specified length using CAAM block
* param[in]: out pointer to place the random bytes
* param[in]: length for the random data bytes.
* param[in]: dev Pointer to job ring device structure
* If operation is successful return 0, otherwise error.
*/
int caam_get_random(struct secure_key_payload *p, enum sk_req_type fetch_rnd,
struct device *dev)
{
struct sk_fetch_rnd_data *fetch_rnd_data = NULL;
struct sk_req *req = NULL;
int ret = 0;
void *temp = NULL;
req = kmalloc(sizeof(struct sk_req), GFP_DMA);
if (!req) {
ret = -ENOMEM;
goto out;
}
req->type = fetch_rnd;
fetch_rnd_data = &(req->req_u.sk_fetch_rnd_data);
/* initialise with key length */
fetch_rnd_data->key_len = p->key_len;
temp = kmalloc(fetch_rnd_data->key_len, GFP_DMA);
if (!temp) {
ret = -ENOMEM;
goto out;
}
fetch_rnd_data->data = temp;
ret = caam_securekey_desc_init(dev, req);
if (ret) {
pr_info("caam_securekey_desc_init failed\n");
goto out;
}
ret = sk_job_submit(dev, req);
if (!ret) {
/*Copy output to key buffer. */
memcpy(p->key, fetch_rnd_data->data, p->key_len);
} else {
ret = -EINVAL;
}
out:
if (req)
kfree(req);
if (temp)
kfree(temp);
return ret;
}
EXPORT_SYMBOL(caam_get_random);
/* key_deblob(struct secure_key_payload *p, enum sk_req_type decap_type
* struct device *dev)
* Deblobify the blob to get the key data and fill in secure key payload struct
* param[in] p pointer to the secure key payload
* param[in] decap_type operation to be done.
* param[in] dev dev Pointer to job ring device structure
* If operation is successful return 0, otherwise error.
*/
int key_deblob(struct secure_key_payload *p, enum sk_req_type decap_type,
struct device *dev)
{
unsigned int blob_len;
struct sk_red_blob_decap *d_blob;
struct sk_req *req = NULL;
int total_sz = 0, *temp = NULL, ret = 0;
req = kmalloc(sizeof(struct sk_req), GFP_DMA);
if (!req) {
ret = -ENOMEM;
goto out;
}
d_blob = &(req->req_u.sk_red_blob_decap);
blob_len = p->blob_len;
req->type = decap_type;
/*
* Red blob size is the blob_len filled in payload struct
* Data_sz i.e. key is the blob_len - blob header size
*/
d_blob->redblob_sz = blob_len;
d_blob->data_sz = blob_len - (SK_BLOB_KEY_SZ + SK_BLOB_MAC_SZ);
total_sz = d_blob->data_sz + d_blob->redblob_sz;
temp = kmalloc(total_sz, GFP_DMA);
if (!temp) {
ret = -ENOMEM;
goto out;
}
req->mem_pointer = temp;
d_blob->redblob = temp;
d_blob->data = d_blob->redblob + d_blob->redblob_sz;
memcpy(d_blob->redblob, p->blob, blob_len);
ret = caam_securekey_desc_init(dev, req);
if (ret) {
pr_info("caam_securekey_desc_init: Failed\n");
goto out;
}
ret = sk_job_submit(dev, req);
if (!ret) {
/*Copy output to key buffer. */
p->key_len = d_blob->data_sz;
memcpy(p->key, d_blob->data, p->key_len);
} else {
ret = -EINVAL;
}
out:
if (temp)
kfree(temp);
if (req)
kfree(req);
return ret;
}
EXPORT_SYMBOL(key_deblob);
/* key_blob(struct secure_key_payload *p, enum sk_req_type encap_type,
* struct device *dev)
* To blobify the key data to get the blob. This blob can only be seen by
* userspace.
* param[in] p pointer to the secure key payload
* param[in] decap_type operation to be done.
* param[in] dev dev Pointer to job ring device structure
* If operation is successful return 0, otherwise error.
*/
int key_blob(struct secure_key_payload *p, enum sk_req_type encap_type,
struct device *dev)
{
unsigned int key_len;
struct sk_red_blob_encap *k_blob;
struct sk_req *req = NULL;
int total_sz = 0, *temp = NULL, ret = 0;
req = kmalloc(sizeof(struct sk_req), GFP_DMA);
if (!req) {
ret = -ENOMEM;
goto out;
}
key_len = p->key_len;
req->type = encap_type;
k_blob = &(req->req_u.sk_red_blob_encap);
/*
* Data_sz i.e. key len and the corresponding blob_len is
* key_len + BLOB header size.
*/
k_blob->data_sz = key_len;
k_blob->redblob_sz = key_len + SK_BLOB_KEY_SZ + SK_BLOB_MAC_SZ;
total_sz = k_blob->data_sz + k_blob->redblob_sz;
temp = kmalloc(total_sz, GFP_DMA);
if (!temp) {
ret = -ENOMEM;
goto out;
}
req->mem_pointer = temp;
k_blob->data = temp;
k_blob->redblob = k_blob->data + k_blob->data_sz;
memcpy(k_blob->data, p->key, key_len);
ret = caam_securekey_desc_init(dev, req);
if (ret) {
pr_info("caam_securekey_desc_init failed\n");
goto out;
}
ret = sk_job_submit(dev, req);
if (!ret) {
/*Copy output to key buffer. */
p->blob_len = k_blob->redblob_sz;
memcpy(p->blob, k_blob->redblob, p->blob_len);
} else {
ret = -EINVAL;
}
out:
if (temp)
kfree(req->mem_pointer);
if (req)
kfree(req);
return ret;
}
EXPORT_SYMBOL(key_blob);