mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-10-30 21:44:27 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			1286 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			1286 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From 808871b2943a386165614daf2e7f5fb5b33e9fd1 Mon Sep 17 00:00:00 2001
 | |
| From: Udit Agarwal <udit.agarwal@nxp.com>
 | |
| Date: Wed, 4 Jul 2018 09:51:59 +0530
 | |
| Subject: [PATCH] security/keys/secure_key: Adds the secure key support based
 | |
|  on CAAM.
 | |
| 
 | |
| Secure keys are derieved using CAAM crypto block.
 | |
| 
 | |
| Secure keys derieved are the random number symmetric keys from CAAM.
 | |
| Blobs corresponding to the key are formed using CAAM. User space
 | |
| will only be able to view the blob of the key.
 | |
| 
 | |
| Signed-off-by: Udit Agarwal <udit.agarwal@nxp.com>
 | |
| Reviewed-by: Sahil Malhotra <sahil.malhotra@nxp.com>
 | |
| ---
 | |
|  Documentation/security/keys/secure-key.rst |  67 ++++
 | |
|  MAINTAINERS                                |  11 +
 | |
|  include/keys/secure-type.h                 |  33 ++
 | |
|  security/keys/Kconfig                      |  11 +
 | |
|  security/keys/Makefile                     |   5 +
 | |
|  security/keys/secure_key.c                 | 339 ++++++++++++++++
 | |
|  security/keys/securekey_desc.c             | 608 +++++++++++++++++++++++++++++
 | |
|  security/keys/securekey_desc.h             | 141 +++++++
 | |
|  8 files changed, 1215 insertions(+)
 | |
|  create mode 100644 Documentation/security/keys/secure-key.rst
 | |
|  create mode 100644 include/keys/secure-type.h
 | |
|  create mode 100644 security/keys/secure_key.c
 | |
|  create mode 100644 security/keys/securekey_desc.c
 | |
|  create mode 100644 security/keys/securekey_desc.h
 | |
| 
 | |
| --- /dev/null
 | |
| +++ b/Documentation/security/keys/secure-key.rst
 | |
| @@ -0,0 +1,67 @@
 | |
| +==========
 | |
| +Secure Key
 | |
| +==========
 | |
| +
 | |
| +Secure key is the new type added to kernel key ring service.
 | |
| +Secure key is a symmetric type key of minimum length 32 bytes
 | |
| +and with maximum possible length to be 128 bytes. It is produced
 | |
| +in kernel using the CAAM crypto engine. Userspace can only see
 | |
| +the blob for the corresponding key. All the blobs are displayed
 | |
| +or loaded in hex ascii.
 | |
| +
 | |
| +Secure key can be created on platforms which supports CAAM
 | |
| +hardware block. Secure key can also be used as a master key to
 | |
| +create the encrypted keys along with the existing key types in
 | |
| +kernel.
 | |
| +
 | |
| +Secure key uses CAAM hardware to generate the key and blobify its
 | |
| +content for userspace. Generated blobs are tied up with the hardware
 | |
| +secret key stored in CAAM, hence the same blob will not be able to
 | |
| +de-blobify with the different secret key on another machine.
 | |
| +
 | |
| +Usage::
 | |
| +
 | |
| +	keyctl add secure <name> "new <keylen>" <ring>
 | |
| +	keyctl load secure <name> "load <hex_blob>" <ring>
 | |
| +	keyctl print <key_id>
 | |
| +
 | |
| +"keyctl add secure" option will create the random data of the
 | |
| +specified key len using CAAM and store it as a key in kernel.
 | |
| +Key contents will be displayed as blobs to the user in hex ascii.
 | |
| +User can input key len from 32 bytes to 128 bytes.
 | |
| +
 | |
| +"keyctl load secure" option will load the blob contents. In kernel,
 | |
| +key will be deirved using input blob and CAAM, along with the secret
 | |
| +key stored in CAAM.
 | |
| +
 | |
| +"keyctl print" will return the hex string of the blob corresponding to
 | |
| +key_id. Returned blob will be of key_len + 48 bytes. Extra 48 bytes are
 | |
| +the header bytes added by the CAAM.
 | |
| +
 | |
| +Example of secure key usage::
 | |
| +
 | |
| +1. Create the secure key with name kmk-master of length 32 bytes::
 | |
| +
 | |
| +	$ keyctl add secure kmk-master "new 32" @u
 | |
| +	46001928
 | |
| +
 | |
| +	$keyctl show
 | |
| +	Session Keyring
 | |
| +	1030783626 --alswrv      0 65534  keyring: _uid_ses.0
 | |
| +	 695927745 --alswrv      0 65534   \_ keyring: _uid.0
 | |
| +	  46001928 --als-rv      0     0       \_ secure: kmk-master
 | |
| +
 | |
| +2. Print the blob contents for the kmk-master key::
 | |
| +
 | |
| +	$ keyctl print 46001928
 | |
| +	d9743445b640f3d59c1670dddc0bc9c2
 | |
| +	34fc9aab7dd05c965e6120025012f029b
 | |
| +	07faa4776c4f6ed02899e35a135531e9a
 | |
| +	6e5c2b51132f9d5aef28f68738e658296
 | |
| +	3fe583177cfe50d2542b659a13039
 | |
| +
 | |
| +	$ keyctl pipe 46001928 > secure_key.blob
 | |
| +
 | |
| +3. Load the blob in the user key ring::
 | |
| +
 | |
| +	$ keyctl load secure kmk-master "load 'cat secure_key.blob'" @u
 | |
| --- a/MAINTAINERS
 | |
| +++ b/MAINTAINERS
 | |
| @@ -9075,6 +9075,17 @@ F:	include/keys/trusted-type.h
 | |
|  F:	security/keys/trusted.c
 | |
|  F:	include/keys/trusted.h
 | |
|  
 | |
| +KEYS-SECURE
 | |
| +M:	Udit Agarwal <udit.agarwal@nxp.com>
 | |
| +R:	Sahil Malhotra <sahil.malhotra@nxp.com>
 | |
| +L:	linux-security-module@vger.kernel.org
 | |
| +L:	keyrings@vger.kernel.org
 | |
| +S:	Supported
 | |
| +F:	include/keys/secure-type.h
 | |
| +F:	security/keys/secure_key.c
 | |
| +F:	security/keys/securekey_desc.c
 | |
| +F:	security/keys/securekey_desc.h
 | |
| +
 | |
|  KEYS/KEYRINGS:
 | |
|  M:	David Howells <dhowells@redhat.com>
 | |
|  M:	Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
 | |
| --- /dev/null
 | |
| +++ b/include/keys/secure-type.h
 | |
| @@ -0,0 +1,33 @@
 | |
| +/* SPDX-License-Identifier: GPL-2.0 */
 | |
| +/*
 | |
| + * Copyright (C) 2018 NXP.
 | |
| + *
 | |
| + */
 | |
| +
 | |
| +#ifndef _KEYS_SECURE_TYPE_H
 | |
| +#define _KEYS_SECURE_TYPE_H
 | |
| +
 | |
| +#include <linux/key.h>
 | |
| +#include <linux/rcupdate.h>
 | |
| +
 | |
| +/* Minimum key size to be used is 32 bytes and maximum key size fixed
 | |
| + * is 128 bytes.
 | |
| + * Blob size to be kept is Maximum key size + blob header added by CAAM.
 | |
| + */
 | |
| +
 | |
| +#define MIN_KEY_SIZE                    32
 | |
| +#define MAX_KEY_SIZE                    128
 | |
| +#define BLOB_HEADER_SIZE		48
 | |
| +
 | |
| +#define MAX_BLOB_SIZE                   (MAX_KEY_SIZE + BLOB_HEADER_SIZE)
 | |
| +
 | |
| +struct secure_key_payload {
 | |
| +	struct rcu_head rcu;
 | |
| +	unsigned int key_len;
 | |
| +	unsigned int blob_len;
 | |
| +	unsigned char key[MAX_KEY_SIZE + 1];
 | |
| +	unsigned char blob[MAX_BLOB_SIZE];
 | |
| +};
 | |
| +
 | |
| +extern struct key_type key_type_secure;
 | |
| +#endif
 | |
| --- a/security/keys/Kconfig
 | |
| +++ b/security/keys/Kconfig
 | |
| @@ -90,6 +90,17 @@ config TRUSTED_KEYS
 | |
|  
 | |
|  	  If you are unsure as to whether this is required, answer N.
 | |
|  
 | |
| +config SECURE_KEYS
 | |
| +	tristate "SECURE_KEYS"
 | |
| +	depends on KEYS && CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR
 | |
| +	help
 | |
| +	  This option provide support for creating secure-type key and blobs
 | |
| +	  in kernel. Secure keys are random number symmetric keys generated
 | |
| +	  from CAAM. The CAAM creates the blobs for the random key.
 | |
| +	  Userspace will only be able to see the blob.
 | |
| +
 | |
| +	  If you are unsure as to whether this is required, answer N.
 | |
| +
 | |
|  config ENCRYPTED_KEYS
 | |
|  	tristate "ENCRYPTED KEYS"
 | |
|  	depends on KEYS
 | |
| --- a/security/keys/Makefile
 | |
| +++ b/security/keys/Makefile
 | |
| @@ -29,4 +29,9 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += key
 | |
|  #
 | |
|  obj-$(CONFIG_BIG_KEYS) += big_key.o
 | |
|  obj-$(CONFIG_TRUSTED_KEYS) += trusted.o
 | |
| +CFLAGS_secure_key.o += -I$(obj)/../../drivers/crypto/caam/
 | |
| +CFLAGS_securekey_desc.o += -I$(obj)/../../drivers/crypto/caam/
 | |
| +obj-$(CONFIG_SECURE_KEYS) += securekey.o
 | |
| +securekey-y := securekey_desc.o \
 | |
| +	       secure_key.o
 | |
|  obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/
 | |
| --- /dev/null
 | |
| +++ b/security/keys/secure_key.c
 | |
| @@ -0,0 +1,339 @@
 | |
| +// SPDX-License-Identifier: GPL-2.0
 | |
| +/* Copyright (C) 2018 NXP
 | |
| + * Secure key is generated using NXP CAAM hardware block. CAAM generates the
 | |
| + * random number (used as a key) and creates its blob for the user.
 | |
| + */
 | |
| +
 | |
| +#include <linux/slab.h>
 | |
| +#include <linux/parser.h>
 | |
| +#include <linux/string.h>
 | |
| +#include <linux/key-type.h>
 | |
| +#include <linux/rcupdate.h>
 | |
| +#include <keys/secure-type.h>
 | |
| +#include <linux/completion.h>
 | |
| +
 | |
| +#include "securekey_desc.h"
 | |
| +
 | |
| +static const char hmac_alg[] = "hmac(sha1)";
 | |
| +static const char hash_alg[] = "sha1";
 | |
| +
 | |
| +static struct crypto_shash *hashalg;
 | |
| +static struct crypto_shash *hmacalg;
 | |
| +
 | |
| +enum {
 | |
| +	error = -1,
 | |
| +	new_key,
 | |
| +	load_blob,
 | |
| +};
 | |
| +
 | |
| +static const match_table_t key_tokens = {
 | |
| +	{new_key, "new"},
 | |
| +	{load_blob, "load"},
 | |
| +	{error, NULL}
 | |
| +};
 | |
| +
 | |
| +static struct secure_key_payload *secure_payload_alloc(struct key *key)
 | |
| +{
 | |
| +	struct secure_key_payload *sec_key = NULL;
 | |
| +	int ret = 0;
 | |
| +
 | |
| +	ret = key_payload_reserve(key, sizeof(*sec_key));
 | |
| +	if (ret < 0)
 | |
| +		goto out;
 | |
| +
 | |
| +	sec_key = kzalloc(sizeof(*sec_key), GFP_KERNEL);
 | |
| +	if (!sec_key)
 | |
| +		goto out;
 | |
| +
 | |
| +out:
 | |
| +	return sec_key;
 | |
| +}
 | |
| +
 | |
| +/*
 | |
| + * parse_inputdata - parse the keyctl input data and fill in the
 | |
| + *		     payload structure for key or its blob.
 | |
| + * param[in]: data pointer to the data to be parsed for creating key.
 | |
| + * param[in]: p pointer to secure key payload structure to fill parsed data
 | |
| + * On success returns 0, otherwise -EINVAL.
 | |
| + */
 | |
| +static int parse_inputdata(char *data, struct secure_key_payload *p)
 | |
| +{
 | |
| +	substring_t args[MAX_OPT_ARGS];
 | |
| +	long keylen = 0;
 | |
| +	int ret = -EINVAL;
 | |
| +	int key_cmd = -EINVAL;
 | |
| +	char *c = NULL;
 | |
| +
 | |
| +	c = strsep(&data, " \t");
 | |
| +	if (!c) {
 | |
| +		ret = -EINVAL;
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	/* Get the keyctl command i.e. new_key or load_blob etc */
 | |
| +	key_cmd = match_token(c, key_tokens, args);
 | |
| +
 | |
| +	switch (key_cmd) {
 | |
| +	case new_key:
 | |
| +		/* first argument is key size */
 | |
| +		c = strsep(&data, " \t");
 | |
| +		if (!c) {
 | |
| +			ret = -EINVAL;
 | |
| +			goto out;
 | |
| +		}
 | |
| +
 | |
| +		ret = kstrtol(c, 10, &keylen);
 | |
| +		if (ret < 0 || keylen < MIN_KEY_SIZE ||
 | |
| +						keylen > MAX_KEY_SIZE) {
 | |
| +			ret = -EINVAL;
 | |
| +			goto out;
 | |
| +		}
 | |
| +
 | |
| +		p->key_len = keylen;
 | |
| +		ret = new_key;
 | |
| +
 | |
| +		break;
 | |
| +	case load_blob:
 | |
| +		/* first argument is blob data for CAAM*/
 | |
| +		c = strsep(&data, " \t");
 | |
| +		if (!c) {
 | |
| +			ret = -EINVAL;
 | |
| +			goto out;
 | |
| +		}
 | |
| +
 | |
| +		/* Blob_len = No of characters in blob/2 */
 | |
| +		p->blob_len = strlen(c) / 2;
 | |
| +		if (p->blob_len > MAX_BLOB_SIZE) {
 | |
| +			ret = -EINVAL;
 | |
| +			goto out;
 | |
| +		}
 | |
| +
 | |
| +		ret = hex2bin(p->blob, c, p->blob_len);
 | |
| +		if (ret < 0) {
 | |
| +			ret = -EINVAL;
 | |
| +			goto out;
 | |
| +		}
 | |
| +		ret = load_blob;
 | |
| +
 | |
| +		break;
 | |
| +	case error:
 | |
| +		ret = -EINVAL;
 | |
| +		break;
 | |
| +	}
 | |
| +
 | |
| +out:
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +/*
 | |
| + * secure_instantiate - create a new secure type key.
 | |
| + * Supports the operation to generate a new key. A random number
 | |
| + * is generated from CAAM as key data and the corresponding red blob
 | |
| + * is formed and stored as key_blob.
 | |
| + * Also supports the operation to load the blob and key is derived using
 | |
| + * that blob from CAAM.
 | |
| + * On success, return 0. Otherwise return errno.
 | |
| + */
 | |
| +static int secure_instantiate(struct key *key,
 | |
| +		struct key_preparsed_payload *prep)
 | |
| +{
 | |
| +	struct secure_key_payload *payload = NULL;
 | |
| +	size_t datalen = prep->datalen;
 | |
| +	char *data = NULL;
 | |
| +	int key_cmd = 0;
 | |
| +	int ret = 0;
 | |
| +	enum sk_req_type sk_op_type;
 | |
| +	struct device *dev = NULL;
 | |
| +
 | |
| +	if (datalen <= 0 || datalen > 32767 || !prep->data) {
 | |
| +		ret = -EINVAL;
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	data = kmalloc(datalen + 1, GFP_KERNEL);
 | |
| +	if (!data) {
 | |
| +		ret = -ENOMEM;
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	memcpy(data, prep->data, datalen);
 | |
| +	data[datalen] = '\0';
 | |
| +
 | |
| +	payload = secure_payload_alloc(key);
 | |
| +	if (!payload) {
 | |
| +		ret = -ENOMEM;
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	/* Allocate caam job ring for operation to be performed from CAAM */
 | |
| +	dev = caam_jr_alloc();
 | |
| +	if (!dev) {
 | |
| +		pr_info("caam_jr_alloc failed\n");
 | |
| +		ret = -ENODEV;
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	key_cmd = parse_inputdata(data, payload);
 | |
| +	if (key_cmd < 0) {
 | |
| +		ret = key_cmd;
 | |
| +		goto out;
 | |
| +	}
 | |
| +
 | |
| +	switch (key_cmd) {
 | |
| +	case load_blob:
 | |
| +		/*
 | |
| +		 * Red blob decryption to be done for load operation
 | |
| +		 * to derive the key.
 | |
| +		 */
 | |
| +		sk_op_type = sk_red_blob_dec;
 | |
| +		ret = key_deblob(payload, sk_op_type, dev);
 | |
| +		if (ret != 0) {
 | |
| +			pr_info("secure_key: key_blob decap fail (%d)\n", ret);
 | |
| +			goto out;
 | |
| +		}
 | |
| +		break;
 | |
| +	case new_key:
 | |
| +		/* Get Random number from caam of the specified length */
 | |
| +		sk_op_type = sk_get_random;
 | |
| +		ret = caam_get_random(payload, sk_op_type, dev);
 | |
| +		if (ret != 0) {
 | |
| +			pr_info("secure_key: get_random fail (%d)\n", ret);
 | |
| +			goto out;
 | |
| +		}
 | |
| +
 | |
| +		/* Generate red blob of key random bytes with CAAM */
 | |
| +		sk_op_type = sk_red_blob_enc;
 | |
| +		ret = key_blob(payload, sk_op_type, dev);
 | |
| +		if (ret != 0) {
 | |
| +			pr_info("secure_key: key_blob encap fail (%d)\n", ret);
 | |
| +			goto out;
 | |
| +		}
 | |
| +		break;
 | |
| +	default:
 | |
| +		ret = -EINVAL;
 | |
| +		goto out;
 | |
| +	}
 | |
| +out:
 | |
| +	if (data)
 | |
| +		kzfree(data);
 | |
| +	if (dev)
 | |
| +		caam_jr_free(dev);
 | |
| +
 | |
| +	if (!ret)
 | |
| +		rcu_assign_keypointer(key, payload);
 | |
| +	else
 | |
| +		kzfree(payload);
 | |
| +
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +/*
 | |
| + * secure_read - copy the  blob data to userspace in hex.
 | |
| + * param[in]: key pointer to key struct
 | |
| + * param[in]: buffer pointer to user data for creating key
 | |
| + * param[in]: buflen is the length of the buffer
 | |
| + * On success, return to userspace the secure key data size.
 | |
| + */
 | |
| +static long secure_read(const struct key *key, char __user *buffer,
 | |
| +			 size_t buflen)
 | |
| +{
 | |
| +	const struct secure_key_payload *p = NULL;
 | |
| +	char *ascii_buf;
 | |
| +	char *bufp;
 | |
| +	int i;
 | |
| +
 | |
| +	p = dereference_key_locked(key);
 | |
| +	if (!p)
 | |
| +		return -EINVAL;
 | |
| +
 | |
| +	if (buffer && buflen >= 2 * p->blob_len) {
 | |
| +		ascii_buf = kmalloc(2 * p->blob_len, GFP_KERNEL);
 | |
| +		if (!ascii_buf)
 | |
| +			return -ENOMEM;
 | |
| +
 | |
| +		bufp = ascii_buf;
 | |
| +		for (i = 0; i < p->blob_len; i++)
 | |
| +			bufp = hex_byte_pack(bufp, p->blob[i]);
 | |
| +		if (copy_to_user(buffer, ascii_buf, 2 * p->blob_len) != 0) {
 | |
| +			kzfree(ascii_buf);
 | |
| +			return -EFAULT;
 | |
| +		}
 | |
| +		kzfree(ascii_buf);
 | |
| +	}
 | |
| +	return 2 * p->blob_len;
 | |
| +}
 | |
| +
 | |
| +/*
 | |
| + * secure_destroy - clear and free the key's payload
 | |
| + */
 | |
| +static void secure_destroy(struct key *key)
 | |
| +{
 | |
| +	kzfree(key->payload.data[0]);
 | |
| +}
 | |
| +
 | |
| +struct key_type key_type_secure = {
 | |
| +	.name = "secure",
 | |
| +	.instantiate = secure_instantiate,
 | |
| +	.destroy = secure_destroy,
 | |
| +	.read = secure_read,
 | |
| +};
 | |
| +EXPORT_SYMBOL_GPL(key_type_secure);
 | |
| +
 | |
| +static void secure_shash_release(void)
 | |
| +{
 | |
| +	if (hashalg)
 | |
| +		crypto_free_shash(hashalg);
 | |
| +	if (hmacalg)
 | |
| +		crypto_free_shash(hmacalg);
 | |
| +}
 | |
| +
 | |
| +static int __init secure_shash_alloc(void)
 | |
| +{
 | |
| +	int ret;
 | |
| +
 | |
| +	hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC);
 | |
| +	if (IS_ERR(hmacalg)) {
 | |
| +		pr_info("secure_key: could not allocate crypto %s\n",
 | |
| +				hmac_alg);
 | |
| +		return PTR_ERR(hmacalg);
 | |
| +	}
 | |
| +
 | |
| +	hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC);
 | |
| +	if (IS_ERR(hashalg)) {
 | |
| +		pr_info("secure_key: could not allocate crypto %s\n",
 | |
| +				hash_alg);
 | |
| +		ret = PTR_ERR(hashalg);
 | |
| +		goto hashalg_fail;
 | |
| +	}
 | |
| +
 | |
| +	return 0;
 | |
| +
 | |
| +hashalg_fail:
 | |
| +	crypto_free_shash(hmacalg);
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +static int __init init_secure_key(void)
 | |
| +{
 | |
| +	int ret;
 | |
| +
 | |
| +	ret = secure_shash_alloc();
 | |
| +	if (ret < 0)
 | |
| +		return ret;
 | |
| +
 | |
| +	ret = register_key_type(&key_type_secure);
 | |
| +	if (ret < 0)
 | |
| +		secure_shash_release();
 | |
| +	return ret;
 | |
| +}
 | |
| +
 | |
| +static void __exit cleanup_secure_key(void)
 | |
| +{
 | |
| +	secure_shash_release();
 | |
| +	unregister_key_type(&key_type_secure);
 | |
| +}
 | |
| +
 | |
| +late_initcall(init_secure_key);
 | |
| +module_exit(cleanup_secure_key);
 | |
| +
 | |
| +MODULE_LICENSE("GPL");
 | |
| --- /dev/null
 | |
| +++ b/security/keys/securekey_desc.c
 | |
| @@ -0,0 +1,608 @@
 | |
| +// 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);
 | |
| --- /dev/null
 | |
| +++ b/security/keys/securekey_desc.h
 | |
| @@ -0,0 +1,141 @@
 | |
| +/* SPDX-License-Identifier: GPL-2.0 */
 | |
| +/*
 | |
| + * Copyright 2018 NXP
 | |
| + *
 | |
| + */
 | |
| +#ifndef _SECUREKEY_DESC_H_
 | |
| +#define _SECUREKEY_DESC_H_
 | |
| +
 | |
| +#include "compat.h"
 | |
| +#include "regs.h"
 | |
| +#include "intern.h"
 | |
| +#include "desc.h"
 | |
| +#include "desc_constr.h"
 | |
| +#include "jr.h"
 | |
| +#include "error.h"
 | |
| +#include "pdb.h"
 | |
| +
 | |
| +#define SK_BLOB_KEY_SZ		32	/* Blob key size. */
 | |
| +#define SK_BLOB_MAC_SZ		16	/* Blob MAC size. */
 | |
| +
 | |
| +/*
 | |
| + * brief defines different kinds of operations supported by this module.
 | |
| + */
 | |
| +enum sk_req_type {
 | |
| +	sk_get_random,
 | |
| +	sk_red_blob_enc,
 | |
| +	sk_red_blob_dec,
 | |
| +};
 | |
| +
 | |
| +
 | |
| +/*
 | |
| + * struct random_des
 | |
| + * param[out] rnd_data output buffer for random data.
 | |
| + */
 | |
| +struct random_desc {
 | |
| +	dma_addr_t rnd_data;
 | |
| +};
 | |
| +
 | |
| +/* struct redblob_encap_desc
 | |
| + * details Structure containing dma address for redblob encapsulation.
 | |
| + * param[in] in_data input data to redblob encap descriptor.
 | |
| + * param[out] redblob output buffer for redblob.
 | |
| + */
 | |
| +struct redblob_encap_desc {
 | |
| +	dma_addr_t in_data;
 | |
| +	dma_addr_t redblob;
 | |
| +};
 | |
| +
 | |
| +/* struct redblob_decap_desc
 | |
| + * details Structure containing dma address for redblob decapsulation.
 | |
| + * param[in] redblob input buffer to redblob decap descriptor.
 | |
| + * param[out] out_data output data from redblob decap descriptor.
 | |
| + */
 | |
| +struct redblob_decap_desc {
 | |
| +	dma_addr_t redblob;
 | |
| +	dma_addr_t out_data;
 | |
| +};
 | |
| +
 | |
| +/* struct sk_desc
 | |
| + * details Structure for securekey descriptor creation.
 | |
| + * param[in] req_type operation supported.
 | |
| + * param[in] dma_u union of struct for supported operation.
 | |
| + */
 | |
| +struct sk_desc {
 | |
| +	u32 req_type;
 | |
| +	union {
 | |
| +		struct redblob_encap_desc redblob_encapdesc;
 | |
| +		struct redblob_decap_desc redblob_decapdesc;
 | |
| +		struct random_desc random_descp;
 | |
| +	} dma_u;
 | |
| +};
 | |
| +
 | |
| +/* struct sk_fetch_rnd_data
 | |
| + * decriptor structure containing key length.
 | |
| + */
 | |
| +struct sk_fetch_rnd_data {
 | |
| +	void *data;
 | |
| +	size_t key_len;
 | |
| +};
 | |
| +
 | |
| +/* struct sk_red_blob_encap
 | |
| + * details Structure containing buffer pointers for redblob encapsulation.
 | |
| + * param[in] data Input data.
 | |
| + * param[in] data_sz size of Input data.
 | |
| + * param[out] redblob output buffer for redblob.
 | |
| + * param[in] redblob_sz size of redblob.
 | |
| + */
 | |
| +struct sk_red_blob_encap {
 | |
| +	void *data;
 | |
| +	uint32_t data_sz;
 | |
| +	void *redblob;
 | |
| +	uint32_t redblob_sz;
 | |
| +};
 | |
| +
 | |
| +/* struct sk_red_blob_decap
 | |
| + * details Structure containing buffer pointers for redblob decapsulation.
 | |
| + * param[in] redblob Input redblob.
 | |
| + * param[in] redblob_sz size of redblob.
 | |
| + * param[out] data output buffer for data.
 | |
| + * param[in] data_sz size of output data.
 | |
| + */
 | |
| +struct sk_red_blob_decap {
 | |
| +	void *redblob;
 | |
| +	uint32_t redblob_sz;
 | |
| +	void *data;
 | |
| +	uint32_t data_sz;
 | |
| +};
 | |
| +
 | |
| +/* struct sk_req
 | |
| + * details Structure for securekey request creation.
 | |
| + * param[in] type operation supported.
 | |
| + * param[in] req_u union of struct for supported operation.
 | |
| + * param[out] ret return status of CAAM operation.
 | |
| + * param[in] mem_pointer memory pointer for allocated kernel memory.
 | |
| + * param[in] desc_pointer Pointer to securekey descriptor creation structure.
 | |
| + * param[in] comp struct completion object.
 | |
| + * param[in] hwdesc contains descriptor instructions.
 | |
| + */
 | |
| +struct sk_req {
 | |
| +	enum sk_req_type type;
 | |
| +	void *arg;
 | |
| +	union {
 | |
| +		struct sk_red_blob_encap sk_red_blob_encap;
 | |
| +		struct sk_red_blob_decap sk_red_blob_decap;
 | |
| +		struct sk_fetch_rnd_data sk_fetch_rnd_data;
 | |
| +	} req_u;
 | |
| +	int ret;
 | |
| +	void *mem_pointer;
 | |
| +	void *desc_pointer;
 | |
| +	struct completion comp;
 | |
| +	u32 hwdesc[MAX_CAAM_DESCSIZE];
 | |
| +};
 | |
| +
 | |
| +int caam_get_random(struct secure_key_payload *p,  enum sk_req_type fetch_rnd,
 | |
| +		    struct device *dev);
 | |
| +int key_blob(struct secure_key_payload *p, enum sk_req_type encap_type,
 | |
| +	     struct device *dev);
 | |
| +int key_deblob(struct secure_key_payload *p, enum sk_req_type decap_type,
 | |
| +	       struct device *dev);
 | |
| +
 | |
| +#endif /*_SECUREKEY_DESC_H_*/
 |