> On Fri, 2018-07-20 at 11:16 +0530, Udit Agarwal wrote: > > 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. > > The term "trusted keys" comes from the usage of the Trusted Platform Module > (TPM). The term "trusted" now also refers to keyrings, which has nothing to do with a > TPM. > > What is the correlation between the term "secure keys" and CAAM? Are "secure keys", as > defined in this patch, limited to a specific HW crypto device? > > Mimi > Yes the secure keys and CAAM are correlated. Secure keys depends on NXP CAAM crypto HW accelerator. Secure key is a random data of length X (passed using keyctl command) & derived using CAAM. Blob of this data is also created using CAAM. Only blob is visible to user space. Regards, Udit > > > > Signed-off-by: Udit Agarwal <udit.agarwal@xxxxxxx> > > Reviewed-by: Sahil Malhotra <sahil.malhotra@xxxxxxx> > > --- > > Documentation/security/keys/secure-key.rst | 67 +++ > > MAINTAINERS | 11 + > > include/keys/secure-type.h | 33 ++ > > security/keys/Kconfig | 11 + > > security/keys/Makefile | 3 + > > security/keys/secure_key.c | 339 ++++++++++++ > > security/keys/securekey_desc.c | 606 +++++++++++++++++++++ > > security/keys/securekey_desc.h | 141 +++++ > > 8 files changed, 1211 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 > > > > diff --git a/Documentation/security/keys/secure-key.rst > > b/Documentation/security/keys/secure-key.rst > > new file mode 100644 > > index 000000000000..0fc3367b00f8 > > --- /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 only 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 > > diff --git a/MAINTAINERS b/MAINTAINERS index > > 9fd5e8808208..654be2ee4b0a 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -7939,6 +7939,17 @@ F: include/keys/trusted-type.h > > F: security/keys/trusted.c > > F: security/keys/trusted.h > > > > +KEYS-SECURE > > +M: Udit Agarwal <udit.agarwal@xxxxxxx> > > +R: Sahil Malhotra <sahil.malhotra@xxxxxxx> > > +L: linux-security-module@xxxxxxxxxxxxxxx > > +L: keyrings@xxxxxxxxxxxxxxx > > +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@xxxxxxxxxx> > > L: keyrings@xxxxxxxxxxxxxxx > > diff --git a/include/keys/secure-type.h b/include/keys/secure-type.h > > new file mode 100644 index 000000000000..5b7a5f144e41 > > --- /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 > > diff --git a/security/keys/Kconfig b/security/keys/Kconfig index > > 6462e6654ccf..7eb138b5a54f 100644 > > --- a/security/keys/Kconfig > > +++ b/security/keys/Kconfig > > @@ -71,6 +71,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 > > diff --git a/security/keys/Makefile b/security/keys/Makefile index > > ef1581b337a3..606ba4efb9e6 100644 > > --- a/security/keys/Makefile > > +++ b/security/keys/Makefile > > @@ -28,4 +28,7 @@ obj-$(CONFIG_KEY_DH_OPERATIONS) += dh.o # > > obj-$(CONFIG_BIG_KEYS) += big_key.o > > obj-$(CONFIG_TRUSTED_KEYS) += trusted.o > > +ccflags-$(CONFIG_SECURE_KEYS) += -I$(obj)/../../drivers/crypto/caam/ > > +obj-$(CONFIG_SECURE_KEYS) += securekey_desc.o > > +obj-$(CONFIG_SECURE_KEYS) += secure_key.o > > obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ diff --git > > a/security/keys/secure_key.c b/security/keys/secure_key.c new file > > mode 100644 index 000000000000..ec8ad4394549 > > --- /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"); > > diff --git a/security/keys/securekey_desc.c > > b/security/keys/securekey_desc.c new file mode 100644 index > > 000000000000..a4fa811a5753 > > --- /dev/null > > +++ b/security/keys/securekey_desc.c > > @@ -0,0 +1,606 @@ > > +// 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; > > +} > > + > > +/* 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; > > +} > > + > > +/* 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.87ea58433208 > > + */ > > + > > + 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; > > + > > +} > > + > > diff --git a/security/keys/securekey_desc.h > > b/security/keys/securekey_desc.h new file mode 100644 index > > 000000000000..0ee26e95b205 > > --- /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_*/