2016-02-22 09:30:59

by Tudor-Dan Ambarus

[permalink] [raw]
Subject: [PATCH 1/3] crypto: scatterwak - Add scatterwalk_sg_copychunks

This patch adds the function scatterwalk_sg_copychunks which writes
a chunk of data from a scatterwalk to another scatterwalk.
It will be used by caam driver to remove the leading zeros of RSA's
algorithm output.

Signed-off-by: Tudor Ambarus <[email protected]>
---
crypto/scatterwalk.c | 26 ++++++++++++++++++++++++++
include/crypto/scatterwalk.h | 2 ++
2 files changed, 28 insertions(+)

diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c
index ea5815c..bc3222d 100644
--- a/crypto/scatterwalk.c
+++ b/crypto/scatterwalk.c
@@ -125,6 +125,32 @@ void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
}
EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy);

+void scatterwalk_sg_copychunks(struct scatter_walk *dest,
+ struct scatter_walk *src, size_t nbytes)
+{
+ for (;;) {
+ unsigned int len_this_page = scatterwalk_pagelen(dest);
+ u8 *vaddr;
+
+ if (len_this_page > nbytes)
+ len_this_page = nbytes;
+
+ vaddr = scatterwalk_map(dest);
+ scatterwalk_copychunks(vaddr, src, len_this_page, 0);
+ scatterwalk_unmap(vaddr);
+
+ scatterwalk_advance(dest, len_this_page);
+
+ if (nbytes == len_this_page)
+ break;
+
+ nbytes -= len_this_page;
+
+ scatterwalk_pagedone(dest, 0, 1);
+ }
+}
+EXPORT_SYMBOL_GPL(scatterwalk_sg_copychunks);
+
int scatterwalk_bytes_sglen(struct scatterlist *sg, int num_bytes)
{
int offset = 0, n = 0;
diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h
index 35f99b6..8b799c5 100644
--- a/include/crypto/scatterwalk.h
+++ b/include/crypto/scatterwalk.h
@@ -86,6 +86,8 @@ static inline void scatterwalk_unmap(void *vaddr)
void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg);
void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
size_t nbytes, int out);
+void scatterwalk_sg_copychunks(struct scatter_walk *dest,
+ struct scatter_walk *src, size_t nbytes);
void *scatterwalk_map(struct scatter_walk *walk);
void scatterwalk_done(struct scatter_walk *walk, int out, int more);

--
1.8.3.1


2016-02-22 09:32:01

by Tudor-Dan Ambarus

[permalink] [raw]
Subject: [PATCH 3/3] crypto: caam - add support for RSA algorithm

Add RSA support to caam driver.

Coauthored-by: Yashpal Dutta <[email protected]>

Signed-off-by: Tudor Ambarus <[email protected]>
---
drivers/crypto/caam/Kconfig | 13 +
drivers/crypto/caam/Makefile | 13 +
drivers/crypto/caam/caam_rsaprivkey.asn1 | 11 +
drivers/crypto/caam/caam_rsapubkey.asn1 | 4 +
drivers/crypto/caam/caampkc.c | 616 +++++++++++++++++++++++++++++++
drivers/crypto/caam/caampkc.h | 106 ++++++
drivers/crypto/caam/desc.h | 2 +
drivers/crypto/caam/pdb.h | 16 +-
drivers/crypto/caam/pkc_desc.c | 136 +++++++
9 files changed, 916 insertions(+), 1 deletion(-)
create mode 100644 drivers/crypto/caam/caam_rsaprivkey.asn1
create mode 100644 drivers/crypto/caam/caam_rsapubkey.asn1
create mode 100644 drivers/crypto/caam/caampkc.c
create mode 100644 drivers/crypto/caam/caampkc.h
create mode 100644 drivers/crypto/caam/pkc_desc.c

diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
index 5652a53..5c1578f 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -99,6 +99,19 @@ config CRYPTO_DEV_FSL_CAAM_AHASH_API
To compile this as a module, choose M here: the module
will be called caamhash.

+config CRYPTO_DEV_FSL_CAAM_PKC_API
+ tristate "Register public key cryptography implementations with Crypto API"
+ depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR
+ default y
+ select CRYPTO_AKCIPHER
+ select ASN1
+ help
+ Selecting this will allow SEC Public key support for RSA.
+ Supported cryptographic primitives: encryption, decryption,
+ signature and verification.
+ To compile this as a module, choose M here: the module
+ will be called caam_pkc.
+
config CRYPTO_DEV_FSL_CAAM_RNG_API
tristate "Register caam device for hwrng API"
depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR
diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile
index 550758a..d4a684c 100644
--- a/drivers/crypto/caam/Makefile
+++ b/drivers/crypto/caam/Makefile
@@ -5,11 +5,24 @@ ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y)
EXTRA_CFLAGS := -DDEBUG
endif

+$(obj)/caam_rsapubkey-asn1.o: $(obj)/caam_rsapubkey-asn1.c \
+ $(obj)/caam_rsapubkey-asn1.h
+$(obj)/caam_rsaprivkey-asn1.o: $(obj)/caam_rsaprivkey-asn1.c \
+ $(obj)/caam_rsaprivkey-asn1.h
+
+clean-files += caam_rsapubkey-asn1.c caam_rsapubkey-asn1.h
+clean-files += caam_rsaprivkey-asn1.c caam_rsapvivkey-asn1.h
+
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o

caam-objs := ctrl.o
caam_jr-objs := jr.o key_gen.o error.o
+caam_pkc-objs := caam_rsapubkey-asn1.o \
+ caam_rsaprivkey-asn1.o \
+ caampkc.o \
+ pkc_desc.o
diff --git a/drivers/crypto/caam/caam_rsaprivkey.asn1 b/drivers/crypto/caam/caam_rsaprivkey.asn1
new file mode 100644
index 0000000..c3a01e2
--- /dev/null
+++ b/drivers/crypto/caam/caam_rsaprivkey.asn1
@@ -0,0 +1,11 @@
+RsaPrivKey ::= SEQUENCE {
+ version INTEGER,
+ n INTEGER ({ caam_rsa_get_n }),
+ e INTEGER ({ caam_rsa_get_e }),
+ d INTEGER ({ caam_rsa_get_d }),
+ prime1 INTEGER,
+ prime2 INTEGER,
+ exponent1 INTEGER,
+ exponent2 INTEGER,
+ coefficient INTEGER
+}
diff --git a/drivers/crypto/caam/caam_rsapubkey.asn1 b/drivers/crypto/caam/caam_rsapubkey.asn1
new file mode 100644
index 0000000..d4bd741
--- /dev/null
+++ b/drivers/crypto/caam/caam_rsapubkey.asn1
@@ -0,0 +1,4 @@
+RsaPubKey ::= SEQUENCE {
+ n INTEGER ({ caam_rsa_get_n }),
+ e INTEGER ({ caam_rsa_get_e })
+}
diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
new file mode 100644
index 0000000..8dd5ff2
--- /dev/null
+++ b/drivers/crypto/caam/caampkc.c
@@ -0,0 +1,616 @@
+/*
+ * caam - Freescale FSL CAAM support for Public Key Cryptography
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * There is no Shared Descriptor for PKC so that the Job Descriptor must carry
+ * all the desired key parameters, input and output pointers.
+ */
+#include <linux/dma-mapping.h>
+#include <linux/fips.h>
+#include "caam_rsapubkey-asn1.h"
+#include "caam_rsaprivkey-asn1.h"
+#include "compat.h"
+#include "caampkc.h"
+#include "sg_sw_sec4.h"
+#include "regs.h"
+#include "intern.h"
+#include "jr.h"
+#include "error.h"
+
+static int rsa_check_key_length(unsigned int len)
+{
+ switch (len) {
+ case 512:
+ case 1024:
+ case 1536:
+ case 2048:
+ case 3072:
+ case 4096:
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int caam_rsa_get_n(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct caam_pkc_context *ctx = context;
+ const char *ptr = value;
+ int ret = -EINVAL;
+
+ while (!*ptr && vlen) {
+ ptr++;
+ vlen--;
+ }
+
+ ctx->key_sz = vlen;
+ /* In FIPS mode only allow key size 2K & 3K */
+ if (fips_enabled && (ctx->key_sz != 256 && ctx->key_sz != 384)) {
+ dev_err(ctx->dev, "CAAM: RSA: key size not allowed in FIPS mode\n");
+ goto err;
+ }
+ /* invalid key size provided */
+ ret = rsa_check_key_length(ctx->key_sz << 3);
+ if (ret)
+ goto err;
+
+ ctx->n = kzalloc(ctx->key_sz, GFP_DMA | GFP_KERNEL);
+ if (!ctx->n) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(ctx->n, ptr, ctx->key_sz);
+
+ return 0;
+err:
+ ctx->key_sz = 0;
+ ctx->n = NULL;
+ return ret;
+}
+
+int caam_rsa_get_e(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct caam_pkc_context *ctx = context;
+ const char *ptr = value;
+
+ while (!*ptr && vlen) {
+ ptr++;
+ vlen--;
+ }
+
+ ctx->e_sz = vlen;
+
+ if (!ctx->key_sz || !vlen || vlen > ctx->key_sz) {
+ ctx->e = NULL;
+ return -EINVAL;
+ }
+
+ ctx->e = kzalloc(ctx->e_sz, GFP_DMA | GFP_KERNEL);
+ if (!ctx->e)
+ return -ENOMEM;
+
+ memcpy(ctx->e, ptr, ctx->e_sz);
+
+ return 0;
+}
+
+int caam_rsa_get_d(void *context, size_t hdrlen, unsigned char tag,
+ const void *value, size_t vlen)
+{
+ struct caam_pkc_context *ctx = context;
+ const char *ptr = value;
+ int ret = -EINVAL;
+
+ while (!*ptr && vlen) {
+ ptr++;
+ vlen--;
+ }
+
+ if (!ctx->key_sz || !vlen || vlen > ctx->key_sz)
+ goto err;
+
+ /* In FIPS mode only allow key size 2K & 3K */
+ if (fips_enabled && (vlen != 256 && vlen != 384)) {
+ dev_err(ctx->dev, "CAAM: RSA: key size not allowed in FIPS mode\n");
+ goto err;
+ }
+
+ ctx->d = kzalloc(ctx->key_sz, GFP_DMA | GFP_KERNEL);
+ if (!ctx->n) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(ctx->d, ptr, vlen);
+
+ return 0;
+err:
+ ctx->d = NULL;
+ return ret;
+}
+
+static void rsa_free_key(struct caam_pkc_context *ctx)
+{
+ kfree(ctx->n);
+ ctx->n = NULL;
+ kfree(ctx->e);
+ ctx->e = NULL;
+
+ if (ctx->d) {
+ memset(ctx->d, '\0', ctx->key_sz);
+ kfree(ctx->d);
+ ctx->d = NULL;
+ }
+
+ ctx->key_sz = 0;
+ ctx->e_sz = 0;
+}
+
+static int caam_rsa_setpubkey(struct crypto_akcipher *tfm, const void *key,
+ unsigned int keylen)
+{
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+ int ret;
+
+ /* Free the old key if any */
+ rsa_free_key(ctx);
+
+ ret = asn1_ber_decoder(&caam_rsapubkey_decoder, ctx, key, keylen);
+ if (ret < 0)
+ goto free;
+
+ if (!ctx->n || !ctx->e) {
+ /* Invalid key provided */
+ ret = -EINVAL;
+ goto free;
+ }
+
+ return 0;
+free:
+ rsa_free_key(ctx);
+ return ret;
+}
+
+static int caam_rsa_setprivkey(struct crypto_akcipher *tfm, const void *key,
+ unsigned int keylen)
+{
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+ int ret;
+
+ /* Free the old key if any */
+ rsa_free_key(ctx);
+
+ ret = asn1_ber_decoder(&caam_rsaprivkey_decoder, ctx, key, keylen);
+ if (ret < 0)
+ goto free;
+
+ if (!ctx->n || !ctx->e || !ctx->d) {
+ /* Invalid key provided */
+ ret = -EINVAL;
+ goto free;
+ }
+
+ return 0;
+free:
+ rsa_free_key(ctx);
+ return ret;
+}
+
+static void rsa_pub_unmap(struct device *dev, struct rsa_edesc *edesc,
+ struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_pub_desc *hw_desc = (struct rsa_pub_desc *)edesc->hw_desc;
+
+ dma_unmap_single(dev, hw_desc->n_dma, ctx->key_sz, DMA_TO_DEVICE);
+ dma_unmap_single(dev, hw_desc->e_dma, ctx->e_sz, DMA_TO_DEVICE);
+ dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
+}
+
+static void rsa_priv_f1_unmap(struct device *dev, struct rsa_edesc *edesc,
+ struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_priv_f1_desc *hw_desc =
+ (struct rsa_priv_f1_desc *)edesc->hw_desc;
+
+ dma_unmap_single(dev, hw_desc->n_dma, ctx->key_sz, DMA_TO_DEVICE);
+ dma_unmap_single(dev, hw_desc->d_dma, ctx->key_sz, DMA_TO_DEVICE);
+ dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
+}
+
+static size_t skip_to_nonzero(u8 *ptr, size_t nbytes)
+{
+ size_t nr_zeros = 0;
+
+ while (!(*ptr) && nbytes) {
+ nbytes--;
+ ptr++;
+ nr_zeros++;
+ }
+
+ return nr_zeros;
+}
+
+static size_t scatterwalk_skip_zeros(struct scatter_walk *walk, size_t nbytes)
+{
+ size_t len_this_page, nr_zeros, cnt = 0;
+ u8 *vaddr, *ptr;
+
+ for (;;) {
+ nr_zeros = 0;
+ len_this_page = scatterwalk_pagelen(walk);
+
+ if (len_this_page > nbytes)
+ len_this_page = nbytes;
+
+ vaddr = scatterwalk_map(walk);
+ ptr = vaddr;
+ nr_zeros = skip_to_nonzero(ptr, len_this_page);
+ scatterwalk_unmap(vaddr);
+
+ /* count total number of zeros */
+ cnt += nr_zeros;
+
+ /* advance scatterwalk to the nonzero data */
+ scatterwalk_advance(walk, nr_zeros);
+
+ if (nr_zeros < len_this_page || nbytes == len_this_page)
+ break;
+
+ nbytes -= len_this_page;
+
+ scatterwalk_pagedone(walk, 0, 1);
+ }
+
+ return cnt;
+}
+
+/*
+ * This function drops the leading zeros and copies the data to the initial
+ * pointer so that it can be freed later on. Returns the updated data length.
+ */
+static size_t drop_leading_zeros(struct scatterlist *sg, size_t nbytes)
+{
+ struct scatter_walk walk_src, walk_dst;
+ size_t nr_zeros = 0;
+
+ scatterwalk_start(&walk_src, sg);
+ nr_zeros = scatterwalk_skip_zeros(&walk_src, nbytes);
+
+ if (nr_zeros) {
+ nbytes = nbytes - nr_zeros;
+
+ scatterwalk_start(&walk_dst, sg);
+ scatterwalk_sg_copychunks(&walk_dst, &walk_src, nbytes);
+ scatterwalk_done(&walk_dst, 0, 0);
+ }
+
+ scatterwalk_done(&walk_src, 0, 0);
+
+ return nbytes;
+}
+
+/* RSA Job Completion handler */
+static void rsa_pub_done(struct device *dev, u32 *desc, u32 err, void *context)
+{
+ struct akcipher_request *req = context;
+ struct rsa_edesc *edesc;
+
+ if (err)
+ caam_jr_strstatus(dev, err);
+
+ /*
+ * RSA's output is expected to be a big integer. Drop the leading
+ * zeros since they are not meaningful in the world of numbers.
+ */
+ req->dst_len = drop_leading_zeros(req->dst, req->dst_len);
+
+ edesc = container_of(desc, struct rsa_edesc, hw_desc[0]);
+
+ rsa_pub_unmap(dev, edesc, req);
+ kfree(edesc);
+
+ akcipher_request_complete(req, err);
+}
+
+static void rsa_priv_f1_done(struct device *dev, u32 *desc, u32 err,
+ void *context)
+{
+ struct akcipher_request *req = context;
+ struct rsa_edesc *edesc;
+
+ if (err)
+ caam_jr_strstatus(dev, err);
+
+ /*
+ * RSA's output is expected to be a big integer. Drop the leading
+ * zeros since they are not meaningful in the world of numbers.
+ */
+ req->dst_len = drop_leading_zeros(req->dst, req->dst_len);
+
+ edesc = container_of(desc, struct rsa_edesc, hw_desc[0]);
+
+ rsa_priv_f1_unmap(dev, edesc, req);
+ kfree(edesc);
+
+ akcipher_request_complete(req, err);
+}
+
+static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req,
+ size_t desclen)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+ struct device *dev = ctx->dev;
+ struct rsa_edesc *edesc;
+ gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG |
+ CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC;
+ int sgc;
+ int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes;
+ int src_nents, dst_nents;
+
+ src_nents = sg_nents_for_len(req->src, req->src_len);
+ dst_nents = sg_nents_for_len(req->dst, req->dst_len);
+
+ if (src_nents > 1)
+ sec4_sg_len = src_nents;
+ if (dst_nents > 1)
+ sec4_sg_len += dst_nents;
+
+ sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry);
+
+ /* allocate space for base edesc, hw desc commands and link tables */
+ edesc = kzalloc(sizeof(*edesc) + desclen + sec4_sg_bytes,
+ GFP_DMA | flags);
+ if (!edesc)
+ return ERR_PTR(-ENOMEM);
+
+ sgc = dma_map_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
+ if (unlikely(!sgc)) {
+ dev_err(dev, "unable to map source\n");
+ goto src_fail;
+ }
+
+ sgc = dma_map_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
+ if (unlikely(!sgc)) {
+ dev_err(dev, "unable to map destination\n");
+ goto dst_fail;
+ }
+
+ edesc->sec4_sg = (void *)edesc + sizeof(*edesc) + desclen;
+
+ sec4_sg_index = 0;
+ if (src_nents > 1) {
+ sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg, 0);
+ sec4_sg_index += src_nents;
+ }
+ if (dst_nents > 1) {
+ sg_to_sec4_sg_last(req->dst, dst_nents,
+ edesc->sec4_sg + sec4_sg_index, 0);
+ }
+
+ /* Save nents for later use in Job Descriptor. */
+ edesc->src_nents = src_nents;
+ edesc->dst_nents = dst_nents;
+
+ if (!sec4_sg_bytes)
+ return edesc;
+
+ edesc->sec4_sg_dma = dma_map_single(dev, edesc->sec4_sg,
+ sec4_sg_bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, edesc->sec4_sg_dma)) {
+ dev_err(dev, "unable to map S/G table\n");
+ goto sec4_sg_fail;
+ }
+
+ return edesc;
+
+sec4_sg_fail:
+ dma_unmap_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
+dst_fail:
+ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
+src_fail:
+ kfree(edesc);
+ return ERR_PTR(-ENOMEM);
+}
+
+static int caam_rsa_enc(struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+ struct device *jrdev = ctx->dev;
+ struct rsa_edesc *edesc = NULL;
+ size_t desclen = sizeof(struct rsa_pub_desc);
+ int ret;
+
+ if (unlikely(!ctx->n || !ctx->e))
+ return -EINVAL;
+
+ if (req->dst_len < ctx->key_sz) {
+ req->dst_len = ctx->key_sz;
+ dev_err(jrdev, "Output buffer length less than parameter n\n");
+ return -EOVERFLOW;
+ }
+
+ /* Allocate extended descriptor. */
+ edesc = rsa_edesc_alloc(req, desclen);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ /* Initialize Job Descriptor. */
+ ret = init_rsa_pub_desc(req, edesc);
+ if (ret)
+ return ret;
+
+ ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_pub_done, req);
+ if (!ret) {
+ ret = -EINPROGRESS;
+ } else {
+ rsa_pub_unmap(jrdev, edesc, req);
+ kfree(edesc);
+ }
+
+ return ret;
+}
+
+static int caam_rsa_dec(struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+ struct device *jrdev = ctx->dev;
+ struct rsa_edesc *edesc = NULL;
+ size_t desclen = sizeof(struct rsa_priv_f1_desc);
+ int ret;
+
+ if (unlikely(!ctx->n || !ctx->d))
+ return -EINVAL;
+
+ if (req->dst_len < ctx->key_sz) {
+ req->dst_len = ctx->key_sz;
+ return -EOVERFLOW;
+ }
+
+ /* Allocate extended descriptor. */
+ edesc = rsa_edesc_alloc(req, desclen);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ /* Initialize Job Descriptor. */
+ ret = init_rsa_priv_f1_desc(req, edesc);
+ if (ret)
+ return ret;
+
+ ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_priv_f1_done, req);
+ if (!ret) {
+ ret = -EINPROGRESS;
+ } else {
+ rsa_priv_f1_unmap(jrdev, edesc, req);
+ kfree(edesc);
+ }
+
+ return ret;
+}
+
+static int caam_rsa_max_size(struct crypto_akcipher *tfm)
+{
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+
+ return (ctx->n) ? ctx->key_sz : -EINVAL;
+}
+
+/* Per session pkc's driver context creation function */
+static int caam_rsa_init_tfm(struct crypto_akcipher *tfm)
+{
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+
+ ctx->dev = caam_jr_alloc();
+
+ if (IS_ERR(ctx->dev)) {
+ dev_err(ctx->dev, "Job Ring Device allocation for transform failed\n");
+ return PTR_ERR(ctx->dev);
+ }
+ return 0;
+}
+
+/* Per session pkc's driver context cleanup function */
+static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm)
+{
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+
+ rsa_free_key(ctx);
+ caam_jr_free(ctx->dev);
+}
+
+static struct akcipher_alg rsa = {
+ .encrypt = caam_rsa_enc,
+ .decrypt = caam_rsa_dec,
+ .sign = caam_rsa_dec,
+ .verify = caam_rsa_enc,
+ .set_pub_key = caam_rsa_setpubkey,
+ .set_priv_key = caam_rsa_setprivkey,
+ .max_size = caam_rsa_max_size,
+ .init = caam_rsa_init_tfm,
+ .exit = caam_rsa_exit_tfm,
+ .base = {
+ .cra_name = "rsa",
+ .cra_driver_name = "rsa-caam",
+ .cra_priority = 3000,
+ .cra_module = THIS_MODULE,
+ .cra_alignmask = 0,
+ .cra_ctxsize = sizeof(struct caam_pkc_context),
+ },
+};
+
+/* Public Key Cryptography module initialization handler */
+static int __init caam_pkc_init(void)
+{
+ struct device_node *dev_node;
+ struct platform_device *pdev;
+ struct device *ctrldev;
+ struct caam_drv_private *priv;
+ u32 cha_inst, pk_inst;
+ int err = 0;
+
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
+ if (!dev_node) {
+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+ if (!dev_node)
+ return -ENODEV;
+ }
+
+ pdev = of_find_device_by_node(dev_node);
+ if (!pdev) {
+ of_node_put(dev_node);
+ return -ENODEV;
+ }
+
+ ctrldev = &pdev->dev;
+ priv = dev_get_drvdata(ctrldev);
+ of_node_put(dev_node);
+
+ /*
+ * If priv is NULL, it's probably because the caam driver wasn't
+ * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
+ */
+ if (!priv)
+ return -ENODEV;
+
+ /* Determine public key hardware accelerator presence. */
+ cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
+ pk_inst = (cha_inst & CHA_ID_LS_PK_MASK) >> CHA_ID_LS_PK_SHIFT;
+
+ /* Do not register algorithms if PKHA is not present. */
+ if (!pk_inst)
+ return -ENODEV;
+
+ rsa.base.cra_flags = 0;
+ err = crypto_register_akcipher(&rsa);
+ if (err)
+ dev_warn(ctrldev, "%s alg registration failed\n",
+ rsa.base.cra_driver_name);
+ else
+ dev_info(ctrldev, "caam algorithms registered in /proc/crypto\n");
+
+ return err;
+}
+
+static void __exit caam_pkc_exit(void)
+{
+ crypto_unregister_akcipher(&rsa);
+}
+
+module_init(caam_pkc_init);
+module_exit(caam_pkc_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("FSL CAAM support for PKC functions of crypto API");
+MODULE_AUTHOR("Freescale Semiconductor");
diff --git a/drivers/crypto/caam/caampkc.h b/drivers/crypto/caam/caampkc.h
new file mode 100644
index 0000000..9967b2d
--- /dev/null
+++ b/drivers/crypto/caam/caampkc.h
@@ -0,0 +1,106 @@
+/*
+ * caam - Freescale FSL CAAM support for Public Key Cryptography descriptors
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * There is no Shared Descriptor for PKC so that the Job Descriptor must carry
+ * all the desired key parameters, input and output pointers.
+ */
+
+#ifndef _PKC_DESC_H_
+#define _PKC_DESC_H_
+
+#include <crypto/akcipher.h>
+#include <crypto/internal/akcipher.h>
+#include "desc_constr.h"
+#include "pdb.h"
+
+/**
+ * Internal context of CAAM driver.
+ * @dev: Job Ring Device pointer for current request
+ * @n: pointer to RSA modulus
+ * @e: pointer to RSA public exponent
+ * @d: pointer to RSA private exponent
+ * @dma_n: dma address of RSA modulus
+ * @dma_e: dma address of RSA public exponent
+ * @dma_d: dma address of RSA private exponent
+ * @key_sz: length in octets of the RSA modulus n
+ * @e_sz: length in octets of the RSA public exponent e
+ */
+struct caam_pkc_context {
+ struct device *dev;
+ u8 *n;
+ u8 *e;
+ u8 *d;
+ dma_addr_t dma_n;
+ dma_addr_t dma_e;
+ dma_addr_t dma_d;
+ size_t key_sz;
+ size_t e_sz;
+};
+
+/**
+ * RSA Pub_Key Descriptor
+ * @desc_hdr: Job Descriptor Header command
+ * @sgf: scatter-gather field
+ * @f_dma: dma address of input data
+ * @g_dma: dma address of ecrypted output data
+ * @n_dma: dma address of RSA public exponent
+ * @dma_e: dma address of RSA public exponent
+ * @f_len: length in octets of the input data
+ * @op: RSA Operation command
+ */
+struct rsa_pub_desc {
+ u32 desc_hdr;
+ u32 sgf;
+ dma_addr_t f_dma;
+ dma_addr_t g_dma;
+ dma_addr_t n_dma;
+ dma_addr_t e_dma;
+ u32 f_len;
+ u32 op;
+} __packed;
+
+/**
+ * Form1 Priv_key Decryption Descriptor.
+ * Private key is represented by (n,d).
+ * @desc_hdr: Job Descriptor Header command
+ * @sgf: scatter-gather field
+ * @g_dma: dma address of ecrypted input data
+ * @f_dma: dma address of output data
+ * @n_dma: dma address of RSA public exponent
+ * @dma_d: dma address of RSA private exponent
+ * @op: RSA Operation command
+ */
+struct rsa_priv_f1_desc {
+ u32 desc_hdr;
+ u32 sgf;
+ dma_addr_t g_dma;
+ dma_addr_t f_dma;
+ dma_addr_t n_dma;
+ dma_addr_t d_dma;
+ u32 op;
+} __packed;
+
+/**
+ * rsa_edesc - s/w-extended rsa descriptor
+ * @src_nents: number of segments in input scatterlist
+ * @dst_nents: number of segments in output scatterlist
+ * @sec4_sg_dma: dma address of h/w link table
+ * @sec4_sg: pointer to h/w link table
+ * @hw_desc: descriptor followed by link tables if any
+ */
+struct rsa_edesc {
+ int src_nents;
+ int dst_nents;
+ dma_addr_t sec4_sg_dma;
+ struct sec4_sg_entry *sec4_sg;
+ u32 hw_desc[];
+};
+
+/* Descriptor construction primitives. */
+int init_rsa_pub_desc(struct akcipher_request *req, struct rsa_edesc *edesc);
+int init_rsa_priv_f1_desc(struct akcipher_request *req,
+ struct rsa_edesc *edesc);
+
+#endif
diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h
index 1e93c6a..7e5c027 100644
--- a/drivers/crypto/caam/desc.h
+++ b/drivers/crypto/caam/desc.h
@@ -454,6 +454,8 @@ struct sec4_sg_entry {
#define OP_PCLID_PUBLICKEYPAIR (0x14 << OP_PCLID_SHIFT)
#define OP_PCLID_DSASIGN (0x15 << OP_PCLID_SHIFT)
#define OP_PCLID_DSAVERIFY (0x16 << OP_PCLID_SHIFT)
+#define OP_PCLID_RSAENC_PUBKEY (0x18 << OP_PCLID_SHIFT)
+#define OP_PCLID_RSADEC_PRVKEY (0x19 << OP_PCLID_SHIFT)

/* Assuming OP_TYPE = OP_TYPE_DECAP_PROTOCOL/ENCAP_PROTOCOL */
#define OP_PCLID_IPSEC (0x01 << OP_PCLID_SHIFT)
diff --git a/drivers/crypto/caam/pdb.h b/drivers/crypto/caam/pdb.h
index 3a87c0c..1c68d7b 100644
--- a/drivers/crypto/caam/pdb.h
+++ b/drivers/crypto/caam/pdb.h
@@ -1,7 +1,7 @@
/*
* CAAM Protocol Data Block (PDB) definition header file
*
- * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
*
*/

@@ -399,4 +399,18 @@ struct dsa_verify_pdb {
u8 *ab; /* only used if ECC processing */
};

+/* RSA Protocol Data Block */
+#define RSA_PDB_SGF_SHIFT 28
+#define RSA_PDB_E_SHIFT 12
+#define RSA_PDB_E_MASK (0xFFF << RSA_PDB_E_SHIFT)
+#define RSA_PDB_D_SHIFT 12
+#define RSA_PDB_D_MASK (0xFFF << RSA_PDB_D_SHIFT)
+
+#define RSA_PDB_SGF_F (0x8 << RSA_PDB_SGF_SHIFT)
+#define RSA_PDB_SGF_G (0x4 << RSA_PDB_SGF_SHIFT)
+#define RSA_PRIV_PDB_SGF_F (0x4 << RSA_PDB_SGF_SHIFT)
+#define RSA_PRIV_PDB_SGF_G (0x8 << RSA_PDB_SGF_SHIFT)
+
+#define RSA_PRIV_KEY_FRM_1 0
+
#endif
diff --git a/drivers/crypto/caam/pkc_desc.c b/drivers/crypto/caam/pkc_desc.c
new file mode 100644
index 0000000..2755c49
--- /dev/null
+++ b/drivers/crypto/caam/pkc_desc.c
@@ -0,0 +1,136 @@
+/*
+ * caam - Freescale FSL CAAM support for Public Key Cryptography descriptors
+ *
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ *
+ * There is no Shared Descriptor for PKC so that the Job Descriptor must carry
+ * all the desired key parameters, input and output pointers.
+ */
+#include "caampkc.h"
+
+/* Descriptor for RSA Public operation */
+int init_rsa_pub_desc(struct akcipher_request *req, struct rsa_edesc *edesc)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+ struct device *dev = ctx->dev;
+ struct rsa_pub_desc *desc = (struct rsa_pub_desc *)edesc->hw_desc;
+ u32 start_idx, desc_size;
+ int sec4_sg_index = 0;
+
+ /*
+ * The PDB has static fields and can be initialized before writing
+ * a specific command. Map the memory first, since it can be a point
+ * of failure.
+ */
+ desc->n_dma = dma_map_single(dev, ctx->n, ctx->key_sz, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, desc->n_dma)) {
+ dev_err(dev, "Unable to map modulus memory\n");
+ goto n_fail;
+ }
+
+ desc->e_dma = dma_map_single(dev, ctx->e, ctx->e_sz, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, desc->e_dma)) {
+ dev_err(dev, "Unable to map exponent memory\n");
+ goto e_fail;
+ }
+
+ desc_size = sizeof(*desc) / CAAM_CMD_SZ;
+ start_idx = (desc_size - 1) & HDR_START_IDX_MASK;
+ init_job_desc(edesc->hw_desc, (start_idx << HDR_START_IDX_SHIFT) |
+ (start_idx & HDR_DESCLEN_MASK) | HDR_ONE);
+
+ sec4_sg_index = 0;
+ if (edesc->src_nents > 1) {
+ desc->sgf |= RSA_PDB_SGF_F;
+ desc->f_dma = edesc->sec4_sg_dma;
+ sec4_sg_index += edesc->src_nents;
+ } else {
+ desc->f_dma = sg_dma_address(req->src);
+ }
+
+ if (edesc->dst_nents > 1) {
+ desc->sgf |= RSA_PDB_SGF_G;
+ desc->g_dma = edesc->sec4_sg_dma +
+ sec4_sg_index * sizeof(struct sec4_sg_entry);
+ } else {
+ desc->g_dma = sg_dma_address(req->dst);
+ }
+
+ desc->sgf |= (ctx->e_sz << RSA_PDB_E_SHIFT) | ctx->key_sz;
+ desc->f_len = req->src_len;
+ desc->op = CMD_OPERATION | OP_TYPE_UNI_PROTOCOL |
+ OP_PCLID_RSAENC_PUBKEY;
+ return 0;
+
+e_fail:
+ dma_unmap_single(dev, desc->n_dma, ctx->key_sz, DMA_TO_DEVICE);
+n_fail:
+ dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
+ kfree(edesc);
+ return -ENOMEM;
+}
+
+/* Descriptor for RSA Private operation */
+int init_rsa_priv_f1_desc(struct akcipher_request *req, struct rsa_edesc *edesc)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
+ struct device *dev = ctx->dev;
+ struct rsa_priv_f1_desc *desc =
+ (struct rsa_priv_f1_desc *)edesc->hw_desc;
+ int sec4_sg_index = 0;
+ u32 start_idx, desc_size;
+
+ /*
+ * The PDB has static fields and can be initialized before writing
+ * a specific command. Map the memory first, since it can be a point
+ * of failure.
+ */
+ desc->n_dma = dma_map_single(dev, ctx->n, ctx->key_sz, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, desc->n_dma)) {
+ dev_err(dev, "Unable to map modulus memory\n");
+ goto n_fail;
+ }
+
+ desc->d_dma = dma_map_single(dev, ctx->d, ctx->key_sz, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, desc->d_dma)) {
+ dev_err(dev, "Unable to map exponent memory\n");
+ goto d_fail;
+ }
+
+ desc_size = sizeof(*desc) / CAAM_CMD_SZ;
+ start_idx = (desc_size - 1) & HDR_START_IDX_MASK;
+ init_job_desc(edesc->hw_desc, (start_idx << HDR_START_IDX_SHIFT) |
+ (start_idx & HDR_DESCLEN_MASK) | HDR_ONE);
+
+ if (edesc->src_nents > 1) {
+ desc->sgf |= RSA_PRIV_PDB_SGF_G;
+ desc->g_dma = edesc->sec4_sg_dma;
+ sec4_sg_index += edesc->src_nents;
+ } else {
+ desc->g_dma = sg_dma_address(req->src);
+ }
+
+ if (edesc->dst_nents > 1) {
+ desc->sgf |= RSA_PRIV_PDB_SGF_F;
+ desc->f_dma = edesc->sec4_sg_dma +
+ sec4_sg_index * sizeof(struct sec4_sg_entry);
+ } else {
+ desc->f_dma = sg_dma_address(req->dst);
+ }
+
+ desc->sgf |= (ctx->key_sz << RSA_PDB_D_SHIFT) | ctx->key_sz;
+ desc->op = CMD_OPERATION | OP_TYPE_UNI_PROTOCOL |
+ OP_PCLID_RSADEC_PRVKEY | RSA_PRIV_KEY_FRM_1;
+ return 0;
+
+d_fail:
+ dma_unmap_single(dev, desc->n_dma, ctx->key_sz, DMA_TO_DEVICE);
+n_fail:
+ dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
+ kfree(edesc);
+ return -ENOMEM;
+}
--
1.8.3.1

2016-02-22 09:32:11

by Tudor-Dan Ambarus

[permalink] [raw]
Subject: [PATCH 2/3] crypto: scatterwalk - export scatterwalk_pagedone

Used in caam driver. Export the symbol since the caam driver
can be built as a module.

Signed-off-by: Tudor Ambarus <[email protected]>
---
crypto/scatterwalk.c | 5 +++--
include/crypto/scatterwalk.h | 2 ++
2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c
index bc3222d..03d34f9 100644
--- a/crypto/scatterwalk.c
+++ b/crypto/scatterwalk.c
@@ -47,8 +47,8 @@ void *scatterwalk_map(struct scatter_walk *walk)
}
EXPORT_SYMBOL_GPL(scatterwalk_map);

-static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
- unsigned int more)
+void scatterwalk_pagedone(struct scatter_walk *walk, int out,
+ unsigned int more)
{
if (out) {
struct page *page;
@@ -69,6 +69,7 @@ static void scatterwalk_pagedone(struct scatter_walk *walk, int out,
scatterwalk_start(walk, sg_next(walk->sg));
}
}
+EXPORT_SYMBOL_GPL(scatterwalk_pagedone);

void scatterwalk_done(struct scatter_walk *walk, int out, int more)
{
diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h
index 8b799c5..6535a20 100644
--- a/include/crypto/scatterwalk.h
+++ b/include/crypto/scatterwalk.h
@@ -89,6 +89,8 @@ void scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
void scatterwalk_sg_copychunks(struct scatter_walk *dest,
struct scatter_walk *src, size_t nbytes);
void *scatterwalk_map(struct scatter_walk *walk);
+void scatterwalk_pagedone(struct scatter_walk *walk, int out,
+ unsigned int more);
void scatterwalk_done(struct scatter_walk *walk, int out, int more);

void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg,
--
1.8.3.1

2016-02-22 10:10:54

by Stephan Müller

[permalink] [raw]
Subject: Re: [PATCH 3/3] crypto: caam - add support for RSA algorithm

Am Montag, 22. Februar 2016, 11:16:17 schrieb Tudor Ambarus:

Hi Tudor,

>Add RSA support to caam driver.
>
>Coauthored-by: Yashpal Dutta <[email protected]>
>
>Signed-off-by: Tudor Ambarus <[email protected]>
>---
> drivers/crypto/caam/Kconfig | 13 +
> drivers/crypto/caam/Makefile | 13 +
> drivers/crypto/caam/caam_rsaprivkey.asn1 | 11 +
> drivers/crypto/caam/caam_rsapubkey.asn1 | 4 +
> drivers/crypto/caam/caampkc.c | 616
>+++++++++++++++++++++++++++++++ drivers/crypto/caam/caampkc.h |
>106 ++++++
> drivers/crypto/caam/desc.h | 2 +
> drivers/crypto/caam/pdb.h | 16 +-
> drivers/crypto/caam/pkc_desc.c | 136 +++++++
> 9 files changed, 916 insertions(+), 1 deletion(-)
> create mode 100644 drivers/crypto/caam/caam_rsaprivkey.asn1
> create mode 100644 drivers/crypto/caam/caam_rsapubkey.asn1
> create mode 100644 drivers/crypto/caam/caampkc.c
> create mode 100644 drivers/crypto/caam/caampkc.h
> create mode 100644 drivers/crypto/caam/pkc_desc.c
>
>diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
>index 5652a53..5c1578f 100644
>--- a/drivers/crypto/caam/Kconfig
>+++ b/drivers/crypto/caam/Kconfig
>@@ -99,6 +99,19 @@ config CRYPTO_DEV_FSL_CAAM_AHASH_API
> To compile this as a module, choose M here: the module
> will be called caamhash.
>
>+config CRYPTO_DEV_FSL_CAAM_PKC_API
>+ tristate "Register public key cryptography implementations with
>Crypto API" + depends on CRYPTO_DEV_FSL_CAAM &&
>CRYPTO_DEV_FSL_CAAM_JR
>+ default y
>+ select CRYPTO_AKCIPHER
>+ select ASN1
>+ help
>+ Selecting this will allow SEC Public key support for RSA.
>+ Supported cryptographic primitives: encryption, decryption,
>+ signature and verification.
>+ To compile this as a module, choose M here: the module
>+ will be called caam_pkc.
>+
> config CRYPTO_DEV_FSL_CAAM_RNG_API
> tristate "Register caam device for hwrng API"
> depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR
>diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile
>index 550758a..d4a684c 100644
>--- a/drivers/crypto/caam/Makefile
>+++ b/drivers/crypto/caam/Makefile
>@@ -5,11 +5,24 @@ ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y)
> EXTRA_CFLAGS := -DDEBUG
> endif
>
>+$(obj)/caam_rsapubkey-asn1.o: $(obj)/caam_rsapubkey-asn1.c \
>+ $(obj)/caam_rsapubkey-asn1.h
>+$(obj)/caam_rsaprivkey-asn1.o: $(obj)/caam_rsaprivkey-asn1.c \
>+ $(obj)/caam_rsaprivkey-asn1.h
>+
>+clean-files += caam_rsapubkey-asn1.c caam_rsapubkey-asn1.h
>+clean-files += caam_rsaprivkey-asn1.c caam_rsapvivkey-asn1.h
>+
> obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o
> obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o
> obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
> obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
> obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o
>+obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o
>
> caam-objs := ctrl.o
> caam_jr-objs := jr.o key_gen.o error.o
>+caam_pkc-objs := caam_rsapubkey-asn1.o \
>+ caam_rsaprivkey-asn1.o \
>+ caampkc.o \
>+ pkc_desc.o
>diff --git a/drivers/crypto/caam/caam_rsaprivkey.asn1
>b/drivers/crypto/caam/caam_rsaprivkey.asn1 new file mode 100644
>index 0000000..c3a01e2
>--- /dev/null
>+++ b/drivers/crypto/caam/caam_rsaprivkey.asn1
>@@ -0,0 +1,11 @@
>+RsaPrivKey ::= SEQUENCE {
>+ version INTEGER,
>+ n INTEGER ({ caam_rsa_get_n }),
>+ e INTEGER ({ caam_rsa_get_e }),
>+ d INTEGER ({ caam_rsa_get_d }),
>+ prime1 INTEGER,
>+ prime2 INTEGER,
>+ exponent1 INTEGER,
>+ exponent2 INTEGER,
>+ coefficient INTEGER
>+}

Why do you define your own ASN.1 sequence? Why not using the common
crypto/rsaprivkey.asn1?

>diff --git a/drivers/crypto/caam/caam_rsapubkey.asn1
>b/drivers/crypto/caam/caam_rsapubkey.asn1 new file mode 100644
>index 0000000..d4bd741
>--- /dev/null
>+++ b/drivers/crypto/caam/caam_rsapubkey.asn1
>@@ -0,0 +1,4 @@
>+RsaPubKey ::= SEQUENCE {
>+ n INTEGER ({ caam_rsa_get_n }),
>+ e INTEGER ({ caam_rsa_get_e })
>+}
>diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
>new file mode 100644
>index 0000000..8dd5ff2
>--- /dev/null
>+++ b/drivers/crypto/caam/caampkc.c
>@@ -0,0 +1,616 @@
>+/*
>+ * caam - Freescale FSL CAAM support for Public Key Cryptography
>+ *
>+ * Copyright 2016 Freescale Semiconductor, Inc.
>+ *
>+ * There is no Shared Descriptor for PKC so that the Job Descriptor must
>carry + * all the desired key parameters, input and output pointers.
>+ */
>+#include <linux/dma-mapping.h>
>+#include <linux/fips.h>
>+#include "caam_rsapubkey-asn1.h"
>+#include "caam_rsaprivkey-asn1.h"
>+#include "compat.h"
>+#include "caampkc.h"
>+#include "sg_sw_sec4.h"
>+#include "regs.h"
>+#include "intern.h"
>+#include "jr.h"
>+#include "error.h"
>+
>+static int rsa_check_key_length(unsigned int len)
>+{
>+ switch (len) {
>+ case 512:
>+ case 1024:
>+ case 1536:
>+ case 2048:
>+ case 3072:
>+ case 4096:
>+ return 0;
>+ }
>+
>+ return -EINVAL;
>+}
>+
>+int caam_rsa_get_n(void *context, size_t hdrlen, unsigned char tag,
>+ const void *value, size_t vlen)
>+{
>+ struct caam_pkc_context *ctx = context;
>+ const char *ptr = value;
>+ int ret = -EINVAL;
>+
>+ while (!*ptr && vlen) {
>+ ptr++;
>+ vlen--;
>+ }
>+
>+ ctx->key_sz = vlen;
>+ /* In FIPS mode only allow key size 2K & 3K */
>+ if (fips_enabled && (ctx->key_sz != 256 && ctx->key_sz != 384)) {
>+ dev_err(ctx->dev, "CAAM: RSA: key size not allowed in FIPS
mode\n");
>+ goto err;
>+ }
>+ /* invalid key size provided */
>+ ret = rsa_check_key_length(ctx->key_sz << 3);
>+ if (ret)
>+ goto err;
>+
>+ ctx->n = kzalloc(ctx->key_sz, GFP_DMA | GFP_KERNEL);
>+ if (!ctx->n) {
>+ ret = -ENOMEM;
>+ goto err;
>+ }
>+
>+ memcpy(ctx->n, ptr, ctx->key_sz);
>+
>+ return 0;
>+err:
>+ ctx->key_sz = 0;
>+ ctx->n = NULL;
>+ return ret;
>+}

This function and the following functions are very similar to the ones in
rsa_helper.c -- shouldn't those be used instead?

>+
>+int caam_rsa_get_e(void *context, size_t hdrlen, unsigned char tag,
>+ const void *value, size_t vlen)
>+{
>+ struct caam_pkc_context *ctx = context;
>+ const char *ptr = value;
>+
>+ while (!*ptr && vlen) {
>+ ptr++;
>+ vlen--;
>+ }
>+
>+ ctx->e_sz = vlen;
>+
>+ if (!ctx->key_sz || !vlen || vlen > ctx->key_sz) {
>+ ctx->e = NULL;
>+ return -EINVAL;
>+ }
>+
>+ ctx->e = kzalloc(ctx->e_sz, GFP_DMA | GFP_KERNEL);
>+ if (!ctx->e)
>+ return -ENOMEM;
>+
>+ memcpy(ctx->e, ptr, ctx->e_sz);
>+
>+ return 0;
>+}
>+
>+int caam_rsa_get_d(void *context, size_t hdrlen, unsigned char tag,
>+ const void *value, size_t vlen)
>+{
>+ struct caam_pkc_context *ctx = context;
>+ const char *ptr = value;
>+ int ret = -EINVAL;
>+
>+ while (!*ptr && vlen) {
>+ ptr++;
>+ vlen--;
>+ }
>+
>+ if (!ctx->key_sz || !vlen || vlen > ctx->key_sz)
>+ goto err;
>+
>+ /* In FIPS mode only allow key size 2K & 3K */
>+ if (fips_enabled && (vlen != 256 && vlen != 384)) {
>+ dev_err(ctx->dev, "CAAM: RSA: key size not allowed in FIPS
mode\n");
>+ goto err;
>+ }
>+
>+ ctx->d = kzalloc(ctx->key_sz, GFP_DMA | GFP_KERNEL);
>+ if (!ctx->n) {
>+ ret = -ENOMEM;
>+ goto err;
>+ }
>+
>+ memcpy(ctx->d, ptr, vlen);
>+
>+ return 0;
>+err:
>+ ctx->d = NULL;
>+ return ret;
>+}
>+
>+static void rsa_free_key(struct caam_pkc_context *ctx)
>+{
>+ kfree(ctx->n);
>+ ctx->n = NULL;
>+ kfree(ctx->e);
>+ ctx->e = NULL;
>+
>+ if (ctx->d) {
>+ memset(ctx->d, '\0', ctx->key_sz);
>+ kfree(ctx->d);

kzfree, please

>+ ctx->d = NULL;
>+ }
>+
>+ ctx->key_sz = 0;
>+ ctx->e_sz = 0;
>+}
>+
>+static int caam_rsa_setpubkey(struct crypto_akcipher *tfm, const void *key,
>+ unsigned int keylen)
>+{
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+ int ret;
>+
>+ /* Free the old key if any */
>+ rsa_free_key(ctx);
>+
>+ ret = asn1_ber_decoder(&caam_rsapubkey_decoder, ctx, key, keylen);
>+ if (ret < 0)
>+ goto free;
>+
>+ if (!ctx->n || !ctx->e) {
>+ /* Invalid key provided */
>+ ret = -EINVAL;
>+ goto free;
>+ }
>+
>+ return 0;
>+free:
>+ rsa_free_key(ctx);
>+ return ret;
>+}
>+
>+static int caam_rsa_setprivkey(struct crypto_akcipher *tfm, const void *key,
>+ unsigned int keylen)
>+{
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+ int ret;
>+
>+ /* Free the old key if any */
>+ rsa_free_key(ctx);
>+
>+ ret = asn1_ber_decoder(&caam_rsaprivkey_decoder, ctx, key, keylen);
>+ if (ret < 0)
>+ goto free;
>+
>+ if (!ctx->n || !ctx->e || !ctx->d) {
>+ /* Invalid key provided */
>+ ret = -EINVAL;
>+ goto free;
>+ }
>+
>+ return 0;
>+free:
>+ rsa_free_key(ctx);
>+ return ret;
>+}
>+
>+static void rsa_pub_unmap(struct device *dev, struct rsa_edesc *edesc,
>+ struct akcipher_request *req)
>+{
>+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+ struct rsa_pub_desc *hw_desc = (struct rsa_pub_desc *)edesc->hw_desc;
>+
>+ dma_unmap_single(dev, hw_desc->n_dma, ctx->key_sz, DMA_TO_DEVICE);
>+ dma_unmap_single(dev, hw_desc->e_dma, ctx->e_sz, DMA_TO_DEVICE);
>+ dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE);
>+ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
>+}
>+
>+static void rsa_priv_f1_unmap(struct device *dev, struct rsa_edesc *edesc,
>+ struct akcipher_request *req)
>+{
>+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+ struct rsa_priv_f1_desc *hw_desc =
>+ (struct rsa_priv_f1_desc *)edesc->hw_desc;
>+
>+ dma_unmap_single(dev, hw_desc->n_dma, ctx->key_sz, DMA_TO_DEVICE);
>+ dma_unmap_single(dev, hw_desc->d_dma, ctx->key_sz, DMA_TO_DEVICE);
>+ dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE);
>+ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
>+}
>+
>+static size_t skip_to_nonzero(u8 *ptr, size_t nbytes)
>+{
>+ size_t nr_zeros = 0;
>+
>+ while (!(*ptr) && nbytes) {
>+ nbytes--;
>+ ptr++;
>+ nr_zeros++;
>+ }
>+
>+ return nr_zeros;
>+}
>+
>+static size_t scatterwalk_skip_zeros(struct scatter_walk *walk, size_t
>nbytes) +{
>+ size_t len_this_page, nr_zeros, cnt = 0;
>+ u8 *vaddr, *ptr;
>+
>+ for (;;) {
>+ nr_zeros = 0;
>+ len_this_page = scatterwalk_pagelen(walk);
>+
>+ if (len_this_page > nbytes)
>+ len_this_page = nbytes;
>+
>+ vaddr = scatterwalk_map(walk);
>+ ptr = vaddr;
>+ nr_zeros = skip_to_nonzero(ptr, len_this_page);
>+ scatterwalk_unmap(vaddr);
>+
>+ /* count total number of zeros */
>+ cnt += nr_zeros;
>+
>+ /* advance scatterwalk to the nonzero data */
>+ scatterwalk_advance(walk, nr_zeros);
>+
>+ if (nr_zeros < len_this_page || nbytes == len_this_page)
>+ break;
>+
>+ nbytes -= len_this_page;
>+
>+ scatterwalk_pagedone(walk, 0, 1);
>+ }
>+
>+ return cnt;
>+}
>+
>+/*
>+ * This function drops the leading zeros and copies the data to the initial
>+ * pointer so that it can be freed later on. Returns the updated data
>length. + */
>+static size_t drop_leading_zeros(struct scatterlist *sg, size_t nbytes)
>+{
>+ struct scatter_walk walk_src, walk_dst;
>+ size_t nr_zeros = 0;
>+
>+ scatterwalk_start(&walk_src, sg);
>+ nr_zeros = scatterwalk_skip_zeros(&walk_src, nbytes);
>+
>+ if (nr_zeros) {
>+ nbytes = nbytes - nr_zeros;
>+
>+ scatterwalk_start(&walk_dst, sg);
>+ scatterwalk_sg_copychunks(&walk_dst, &walk_src, nbytes);
>+ scatterwalk_done(&walk_dst, 0, 0);
>+ }
>+
>+ scatterwalk_done(&walk_src, 0, 0);
>+
>+ return nbytes;
>+}
>+
>+/* RSA Job Completion handler */
>+static void rsa_pub_done(struct device *dev, u32 *desc, u32 err, void
>*context) +{
>+ struct akcipher_request *req = context;
>+ struct rsa_edesc *edesc;
>+
>+ if (err)
>+ caam_jr_strstatus(dev, err);
>+
>+ /*
>+ * RSA's output is expected to be a big integer. Drop the leading
>+ * zeros since they are not meaningful in the world of numbers.
>+ */
>+ req->dst_len = drop_leading_zeros(req->dst, req->dst_len);
>+
>+ edesc = container_of(desc, struct rsa_edesc, hw_desc[0]);
>+
>+ rsa_pub_unmap(dev, edesc, req);
>+ kfree(edesc);
>+
>+ akcipher_request_complete(req, err);
>+}
>+
>+static void rsa_priv_f1_done(struct device *dev, u32 *desc, u32 err,
>+ void *context)
>+{
>+ struct akcipher_request *req = context;
>+ struct rsa_edesc *edesc;
>+
>+ if (err)
>+ caam_jr_strstatus(dev, err);
>+
>+ /*
>+ * RSA's output is expected to be a big integer. Drop the leading
>+ * zeros since they are not meaningful in the world of numbers.
>+ */
>+ req->dst_len = drop_leading_zeros(req->dst, req->dst_len);
>+
>+ edesc = container_of(desc, struct rsa_edesc, hw_desc[0]);
>+
>+ rsa_priv_f1_unmap(dev, edesc, req);
>+ kfree(edesc);
>+
>+ akcipher_request_complete(req, err);
>+}
>+
>+static struct rsa_edesc *rsa_edesc_alloc(struct akcipher_request *req,
>+ size_t desclen)
>+{
>+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+ struct device *dev = ctx->dev;
>+ struct rsa_edesc *edesc;
>+ gfp_t flags = (req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG |
>+ CRYPTO_TFM_REQ_MAY_SLEEP)) ? GFP_KERNEL : GFP_ATOMIC;
>+ int sgc;
>+ int sec4_sg_index, sec4_sg_len = 0, sec4_sg_bytes;
>+ int src_nents, dst_nents;
>+
>+ src_nents = sg_nents_for_len(req->src, req->src_len);
>+ dst_nents = sg_nents_for_len(req->dst, req->dst_len);
>+
>+ if (src_nents > 1)
>+ sec4_sg_len = src_nents;
>+ if (dst_nents > 1)
>+ sec4_sg_len += dst_nents;
>+
>+ sec4_sg_bytes = sec4_sg_len * sizeof(struct sec4_sg_entry);
>+
>+ /* allocate space for base edesc, hw desc commands and link tables */
>+ edesc = kzalloc(sizeof(*edesc) + desclen + sec4_sg_bytes,
>+ GFP_DMA | flags);
>+ if (!edesc)
>+ return ERR_PTR(-ENOMEM);
>+
>+ sgc = dma_map_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
>+ if (unlikely(!sgc)) {
>+ dev_err(dev, "unable to map source\n");
>+ goto src_fail;
>+ }
>+
>+ sgc = dma_map_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
>+ if (unlikely(!sgc)) {
>+ dev_err(dev, "unable to map destination\n");
>+ goto dst_fail;
>+ }
>+
>+ edesc->sec4_sg = (void *)edesc + sizeof(*edesc) + desclen;
>+
>+ sec4_sg_index = 0;
>+ if (src_nents > 1) {
>+ sg_to_sec4_sg_last(req->src, src_nents, edesc->sec4_sg, 0);
>+ sec4_sg_index += src_nents;
>+ }
>+ if (dst_nents > 1) {
>+ sg_to_sec4_sg_last(req->dst, dst_nents,
>+ edesc->sec4_sg + sec4_sg_index, 0);
>+ }
>+
>+ /* Save nents for later use in Job Descriptor. */
>+ edesc->src_nents = src_nents;
>+ edesc->dst_nents = dst_nents;
>+
>+ if (!sec4_sg_bytes)
>+ return edesc;
>+
>+ edesc->sec4_sg_dma = dma_map_single(dev, edesc->sec4_sg,
>+ sec4_sg_bytes, DMA_TO_DEVICE);
>+ if (dma_mapping_error(dev, edesc->sec4_sg_dma)) {
>+ dev_err(dev, "unable to map S/G table\n");
>+ goto sec4_sg_fail;
>+ }
>+
>+ return edesc;
>+
>+sec4_sg_fail:
>+ dma_unmap_sg(dev, req->dst, dst_nents, DMA_FROM_DEVICE);
>+dst_fail:
>+ dma_unmap_sg(dev, req->src, src_nents, DMA_TO_DEVICE);
>+src_fail:
>+ kfree(edesc);
>+ return ERR_PTR(-ENOMEM);
>+}
>+
>+static int caam_rsa_enc(struct akcipher_request *req)
>+{
>+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+ struct device *jrdev = ctx->dev;
>+ struct rsa_edesc *edesc = NULL;
>+ size_t desclen = sizeof(struct rsa_pub_desc);
>+ int ret;
>+
>+ if (unlikely(!ctx->n || !ctx->e))
>+ return -EINVAL;
>+
>+ if (req->dst_len < ctx->key_sz) {
>+ req->dst_len = ctx->key_sz;
>+ dev_err(jrdev, "Output buffer length less than parameter
n\n");
>+ return -EOVERFLOW;
>+ }
>+
>+ /* Allocate extended descriptor. */
>+ edesc = rsa_edesc_alloc(req, desclen);
>+ if (IS_ERR(edesc))
>+ return PTR_ERR(edesc);
>+
>+ /* Initialize Job Descriptor. */
>+ ret = init_rsa_pub_desc(req, edesc);
>+ if (ret)
>+ return ret;
>+
>+ ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_pub_done, req);
>+ if (!ret) {
>+ ret = -EINPROGRESS;
>+ } else {
>+ rsa_pub_unmap(jrdev, edesc, req);
>+ kfree(edesc);
>+ }
>+
>+ return ret;
>+}
>+
>+static int caam_rsa_dec(struct akcipher_request *req)
>+{
>+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+ struct device *jrdev = ctx->dev;
>+ struct rsa_edesc *edesc = NULL;
>+ size_t desclen = sizeof(struct rsa_priv_f1_desc);
>+ int ret;
>+
>+ if (unlikely(!ctx->n || !ctx->d))
>+ return -EINVAL;
>+
>+ if (req->dst_len < ctx->key_sz) {
>+ req->dst_len = ctx->key_sz;
>+ return -EOVERFLOW;
>+ }
>+
>+ /* Allocate extended descriptor. */
>+ edesc = rsa_edesc_alloc(req, desclen);
>+ if (IS_ERR(edesc))
>+ return PTR_ERR(edesc);
>+
>+ /* Initialize Job Descriptor. */
>+ ret = init_rsa_priv_f1_desc(req, edesc);
>+ if (ret)
>+ return ret;
>+
>+ ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_priv_f1_done, req);
>+ if (!ret) {
>+ ret = -EINPROGRESS;
>+ } else {
>+ rsa_priv_f1_unmap(jrdev, edesc, req);
>+ kfree(edesc);
>+ }
>+
>+ return ret;
>+}
>+
>+static int caam_rsa_max_size(struct crypto_akcipher *tfm)
>+{
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+
>+ return (ctx->n) ? ctx->key_sz : -EINVAL;
>+}
>+
>+/* Per session pkc's driver context creation function */
>+static int caam_rsa_init_tfm(struct crypto_akcipher *tfm)
>+{
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+
>+ ctx->dev = caam_jr_alloc();
>+
>+ if (IS_ERR(ctx->dev)) {
>+ dev_err(ctx->dev, "Job Ring Device allocation for transform
failed\n");
>+ return PTR_ERR(ctx->dev);
>+ }
>+ return 0;
>+}
>+
>+/* Per session pkc's driver context cleanup function */
>+static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm)
>+{
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+
>+ rsa_free_key(ctx);
>+ caam_jr_free(ctx->dev);
>+}
>+
>+static struct akcipher_alg rsa = {
>+ .encrypt = caam_rsa_enc,
>+ .decrypt = caam_rsa_dec,
>+ .sign = caam_rsa_dec,
>+ .verify = caam_rsa_enc,
>+ .set_pub_key = caam_rsa_setpubkey,
>+ .set_priv_key = caam_rsa_setprivkey,
>+ .max_size = caam_rsa_max_size,
>+ .init = caam_rsa_init_tfm,
>+ .exit = caam_rsa_exit_tfm,
>+ .base = {
>+ .cra_name = "rsa",
>+ .cra_driver_name = "rsa-caam",
>+ .cra_priority = 3000,
>+ .cra_module = THIS_MODULE,
>+ .cra_alignmask = 0,
>+ .cra_ctxsize = sizeof(struct caam_pkc_context),
>+ },
>+};
>+
>+/* Public Key Cryptography module initialization handler */
>+static int __init caam_pkc_init(void)
>+{
>+ struct device_node *dev_node;
>+ struct platform_device *pdev;
>+ struct device *ctrldev;
>+ struct caam_drv_private *priv;
>+ u32 cha_inst, pk_inst;
>+ int err = 0;
>+
>+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
>+ if (!dev_node) {
>+ dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
>+ if (!dev_node)
>+ return -ENODEV;
>+ }
>+
>+ pdev = of_find_device_by_node(dev_node);
>+ if (!pdev) {
>+ of_node_put(dev_node);
>+ return -ENODEV;
>+ }
>+
>+ ctrldev = &pdev->dev;
>+ priv = dev_get_drvdata(ctrldev);
>+ of_node_put(dev_node);
>+
>+ /*
>+ * If priv is NULL, it's probably because the caam driver wasn't
>+ * properly initialized (e.g. RNG4 init failed). Thus, bail out here.
>+ */
>+ if (!priv)
>+ return -ENODEV;
>+
>+ /* Determine public key hardware accelerator presence. */
>+ cha_inst = rd_reg32(&priv->ctrl->perfmon.cha_num_ls);
>+ pk_inst = (cha_inst & CHA_ID_LS_PK_MASK) >> CHA_ID_LS_PK_SHIFT;
>+
>+ /* Do not register algorithms if PKHA is not present. */
>+ if (!pk_inst)
>+ return -ENODEV;
>+
>+ rsa.base.cra_flags = 0;
>+ err = crypto_register_akcipher(&rsa);
>+ if (err)
>+ dev_warn(ctrldev, "%s alg registration failed\n",
>+ rsa.base.cra_driver_name);
>+ else
>+ dev_info(ctrldev, "caam algorithms registered in
/proc/crypto\n");
>+
>+ return err;
>+}
>+
>+static void __exit caam_pkc_exit(void)
>+{
>+ crypto_unregister_akcipher(&rsa);
>+}
>+
>+module_init(caam_pkc_init);
>+module_exit(caam_pkc_exit);
>+
>+MODULE_LICENSE("Dual BSD/GPL");
>+MODULE_DESCRIPTION("FSL CAAM support for PKC functions of crypto API");
>+MODULE_AUTHOR("Freescale Semiconductor");
>diff --git a/drivers/crypto/caam/caampkc.h b/drivers/crypto/caam/caampkc.h
>new file mode 100644
>index 0000000..9967b2d
>--- /dev/null
>+++ b/drivers/crypto/caam/caampkc.h
>@@ -0,0 +1,106 @@
>+/*
>+ * caam - Freescale FSL CAAM support for Public Key Cryptography descriptors
>+ *
>+ * Copyright 2016 Freescale Semiconductor, Inc.
>+ *
>+ * There is no Shared Descriptor for PKC so that the Job Descriptor must
>carry + * all the desired key parameters, input and output pointers.
>+ */
>+
>+#ifndef _PKC_DESC_H_
>+#define _PKC_DESC_H_
>+
>+#include <crypto/akcipher.h>
>+#include <crypto/internal/akcipher.h>
>+#include "desc_constr.h"
>+#include "pdb.h"
>+
>+/**
>+ * Internal context of CAAM driver.
>+ * @dev: Job Ring Device pointer for current request
>+ * @n: pointer to RSA modulus
>+ * @e: pointer to RSA public exponent
>+ * @d: pointer to RSA private exponent
>+ * @dma_n: dma address of RSA modulus
>+ * @dma_e: dma address of RSA public exponent
>+ * @dma_d: dma address of RSA private exponent
>+ * @key_sz: length in octets of the RSA modulus n
>+ * @e_sz: length in octets of the RSA public exponent e
>+ */
>+struct caam_pkc_context {
>+ struct device *dev;
>+ u8 *n;
>+ u8 *e;
>+ u8 *d;
>+ dma_addr_t dma_n;
>+ dma_addr_t dma_e;
>+ dma_addr_t dma_d;
>+ size_t key_sz;
>+ size_t e_sz;
>+};
>+
>+/**
>+ * RSA Pub_Key Descriptor
>+ * @desc_hdr: Job Descriptor Header command
>+ * @sgf: scatter-gather field
>+ * @f_dma: dma address of input data
>+ * @g_dma: dma address of ecrypted output data
>+ * @n_dma: dma address of RSA public exponent
>+ * @dma_e: dma address of RSA public exponent
>+ * @f_len: length in octets of the input data
>+ * @op: RSA Operation command
>+ */
>+struct rsa_pub_desc {
>+ u32 desc_hdr;
>+ u32 sgf;
>+ dma_addr_t f_dma;
>+ dma_addr_t g_dma;
>+ dma_addr_t n_dma;
>+ dma_addr_t e_dma;
>+ u32 f_len;
>+ u32 op;
>+} __packed;
>+
>+/**
>+ * Form1 Priv_key Decryption Descriptor.
>+ * Private key is represented by (n,d).
>+ * @desc_hdr: Job Descriptor Header command
>+ * @sgf: scatter-gather field
>+ * @g_dma: dma address of ecrypted input data
>+ * @f_dma: dma address of output data
>+ * @n_dma: dma address of RSA public exponent
>+ * @dma_d: dma address of RSA private exponent
>+ * @op: RSA Operation command
>+ */
>+struct rsa_priv_f1_desc {
>+ u32 desc_hdr;
>+ u32 sgf;
>+ dma_addr_t g_dma;
>+ dma_addr_t f_dma;
>+ dma_addr_t n_dma;
>+ dma_addr_t d_dma;
>+ u32 op;
>+} __packed;
>+
>+/**
>+ * rsa_edesc - s/w-extended rsa descriptor
>+ * @src_nents: number of segments in input scatterlist
>+ * @dst_nents: number of segments in output scatterlist
>+ * @sec4_sg_dma: dma address of h/w link table
>+ * @sec4_sg: pointer to h/w link table
>+ * @hw_desc: descriptor followed by link tables if any
>+ */
>+struct rsa_edesc {
>+ int src_nents;
>+ int dst_nents;
>+ dma_addr_t sec4_sg_dma;
>+ struct sec4_sg_entry *sec4_sg;
>+ u32 hw_desc[];
>+};
>+
>+/* Descriptor construction primitives. */
>+int init_rsa_pub_desc(struct akcipher_request *req, struct rsa_edesc
>*edesc); +int init_rsa_priv_f1_desc(struct akcipher_request *req,
>+ struct rsa_edesc *edesc);
>+
>+#endif
>diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h
>index 1e93c6a..7e5c027 100644
>--- a/drivers/crypto/caam/desc.h
>+++ b/drivers/crypto/caam/desc.h
>@@ -454,6 +454,8 @@ struct sec4_sg_entry {
> #define OP_PCLID_PUBLICKEYPAIR (0x14 << OP_PCLID_SHIFT)
> #define OP_PCLID_DSASIGN (0x15 << OP_PCLID_SHIFT)
> #define OP_PCLID_DSAVERIFY (0x16 << OP_PCLID_SHIFT)
>+#define OP_PCLID_RSAENC_PUBKEY (0x18 << OP_PCLID_SHIFT)
>+#define OP_PCLID_RSADEC_PRVKEY (0x19 << OP_PCLID_SHIFT)
>
> /* Assuming OP_TYPE = OP_TYPE_DECAP_PROTOCOL/ENCAP_PROTOCOL */
> #define OP_PCLID_IPSEC (0x01 << OP_PCLID_SHIFT)
>diff --git a/drivers/crypto/caam/pdb.h b/drivers/crypto/caam/pdb.h
>index 3a87c0c..1c68d7b 100644
>--- a/drivers/crypto/caam/pdb.h
>+++ b/drivers/crypto/caam/pdb.h
>@@ -1,7 +1,7 @@
> /*
> * CAAM Protocol Data Block (PDB) definition header file
> *
>- * Copyright 2008-2012 Freescale Semiconductor, Inc.
>+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
> *
> */
>
>@@ -399,4 +399,18 @@ struct dsa_verify_pdb {
> u8 *ab; /* only used if ECC processing */
> };
>
>+/* RSA Protocol Data Block */
>+#define RSA_PDB_SGF_SHIFT 28
>+#define RSA_PDB_E_SHIFT 12
>+#define RSA_PDB_E_MASK (0xFFF << RSA_PDB_E_SHIFT)
>+#define RSA_PDB_D_SHIFT 12
>+#define RSA_PDB_D_MASK (0xFFF << RSA_PDB_D_SHIFT)
>+
>+#define RSA_PDB_SGF_F (0x8 << RSA_PDB_SGF_SHIFT)
>+#define RSA_PDB_SGF_G (0x4 << RSA_PDB_SGF_SHIFT)
>+#define RSA_PRIV_PDB_SGF_F (0x4 << RSA_PDB_SGF_SHIFT)
>+#define RSA_PRIV_PDB_SGF_G (0x8 << RSA_PDB_SGF_SHIFT)
>+
>+#define RSA_PRIV_KEY_FRM_1 0
>+
> #endif
>diff --git a/drivers/crypto/caam/pkc_desc.c b/drivers/crypto/caam/pkc_desc.c
>new file mode 100644
>index 0000000..2755c49
>--- /dev/null
>+++ b/drivers/crypto/caam/pkc_desc.c
>@@ -0,0 +1,136 @@
>+/*
>+ * caam - Freescale FSL CAAM support for Public Key Cryptography descriptors
>+ *
>+ * Copyright 2016 Freescale Semiconductor, Inc.
>+ *
>+ * There is no Shared Descriptor for PKC so that the Job Descriptor must
>carry + * all the desired key parameters, input and output pointers.
>+ */
>+#include "caampkc.h"
>+
>+/* Descriptor for RSA Public operation */
>+int init_rsa_pub_desc(struct akcipher_request *req, struct rsa_edesc *edesc)
>+{
>+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+ struct device *dev = ctx->dev;
>+ struct rsa_pub_desc *desc = (struct rsa_pub_desc *)edesc->hw_desc;
>+ u32 start_idx, desc_size;
>+ int sec4_sg_index = 0;
>+
>+ /*
>+ * The PDB has static fields and can be initialized before writing
>+ * a specific command. Map the memory first, since it can be a point
>+ * of failure.
>+ */
>+ desc->n_dma = dma_map_single(dev, ctx->n, ctx->key_sz, DMA_TO_DEVICE);
>+ if (dma_mapping_error(dev, desc->n_dma)) {
>+ dev_err(dev, "Unable to map modulus memory\n");
>+ goto n_fail;
>+ }
>+
>+ desc->e_dma = dma_map_single(dev, ctx->e, ctx->e_sz, DMA_TO_DEVICE);
>+ if (dma_mapping_error(dev, desc->e_dma)) {
>+ dev_err(dev, "Unable to map exponent memory\n");
>+ goto e_fail;
>+ }
>+
>+ desc_size = sizeof(*desc) / CAAM_CMD_SZ;
>+ start_idx = (desc_size - 1) & HDR_START_IDX_MASK;
>+ init_job_desc(edesc->hw_desc, (start_idx << HDR_START_IDX_SHIFT) |
>+ (start_idx & HDR_DESCLEN_MASK) | HDR_ONE);
>+
>+ sec4_sg_index = 0;
>+ if (edesc->src_nents > 1) {
>+ desc->sgf |= RSA_PDB_SGF_F;
>+ desc->f_dma = edesc->sec4_sg_dma;
>+ sec4_sg_index += edesc->src_nents;
>+ } else {
>+ desc->f_dma = sg_dma_address(req->src);
>+ }
>+
>+ if (edesc->dst_nents > 1) {
>+ desc->sgf |= RSA_PDB_SGF_G;
>+ desc->g_dma = edesc->sec4_sg_dma +
>+ sec4_sg_index * sizeof(struct sec4_sg_entry);
>+ } else {
>+ desc->g_dma = sg_dma_address(req->dst);
>+ }
>+
>+ desc->sgf |= (ctx->e_sz << RSA_PDB_E_SHIFT) | ctx->key_sz;
>+ desc->f_len = req->src_len;
>+ desc->op = CMD_OPERATION | OP_TYPE_UNI_PROTOCOL |
>+ OP_PCLID_RSAENC_PUBKEY;
>+ return 0;
>+
>+e_fail:
>+ dma_unmap_single(dev, desc->n_dma, ctx->key_sz, DMA_TO_DEVICE);
>+n_fail:
>+ dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE);
>+ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
>+ kfree(edesc);
>+ return -ENOMEM;
>+}
>+
>+/* Descriptor for RSA Private operation */
>+int init_rsa_priv_f1_desc(struct akcipher_request *req, struct rsa_edesc
>*edesc) +{
>+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
>+ struct caam_pkc_context *ctx = akcipher_tfm_ctx(tfm);
>+ struct device *dev = ctx->dev;
>+ struct rsa_priv_f1_desc *desc =
>+ (struct rsa_priv_f1_desc *)edesc->hw_desc;
>+ int sec4_sg_index = 0;
>+ u32 start_idx, desc_size;
>+
>+ /*
>+ * The PDB has static fields and can be initialized before writing
>+ * a specific command. Map the memory first, since it can be a point
>+ * of failure.
>+ */
>+ desc->n_dma = dma_map_single(dev, ctx->n, ctx->key_sz, DMA_TO_DEVICE);
>+ if (dma_mapping_error(dev, desc->n_dma)) {
>+ dev_err(dev, "Unable to map modulus memory\n");
>+ goto n_fail;
>+ }
>+
>+ desc->d_dma = dma_map_single(dev, ctx->d, ctx->key_sz, DMA_TO_DEVICE);
>+ if (dma_mapping_error(dev, desc->d_dma)) {
>+ dev_err(dev, "Unable to map exponent memory\n");
>+ goto d_fail;
>+ }
>+
>+ desc_size = sizeof(*desc) / CAAM_CMD_SZ;
>+ start_idx = (desc_size - 1) & HDR_START_IDX_MASK;
>+ init_job_desc(edesc->hw_desc, (start_idx << HDR_START_IDX_SHIFT) |
>+ (start_idx & HDR_DESCLEN_MASK) | HDR_ONE);
>+
>+ if (edesc->src_nents > 1) {
>+ desc->sgf |= RSA_PRIV_PDB_SGF_G;
>+ desc->g_dma = edesc->sec4_sg_dma;
>+ sec4_sg_index += edesc->src_nents;
>+ } else {
>+ desc->g_dma = sg_dma_address(req->src);
>+ }
>+
>+ if (edesc->dst_nents > 1) {
>+ desc->sgf |= RSA_PRIV_PDB_SGF_F;
>+ desc->f_dma = edesc->sec4_sg_dma +
>+ sec4_sg_index * sizeof(struct sec4_sg_entry);
>+ } else {
>+ desc->f_dma = sg_dma_address(req->dst);
>+ }
>+
>+ desc->sgf |= (ctx->key_sz << RSA_PDB_D_SHIFT) | ctx->key_sz;
>+ desc->op = CMD_OPERATION | OP_TYPE_UNI_PROTOCOL |
>+ OP_PCLID_RSADEC_PRVKEY | RSA_PRIV_KEY_FRM_1;
>+ return 0;
>+
>+d_fail:
>+ dma_unmap_single(dev, desc->n_dma, ctx->key_sz, DMA_TO_DEVICE);
>+n_fail:
>+ dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE);
>+ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
>+ kfree(edesc);
>+ return -ENOMEM;
>+}


Ciao
Stephan

2016-02-22 12:12:59

by Tudor-Dan Ambarus

[permalink] [raw]
Subject: RE: [PATCH 3/3] crypto: caam - add support for RSA algorithm

Hi Stephan,

> -----Original Message-----
> >+++ b/drivers/crypto/caam/caam_rsaprivkey.asn1
> >@@ -0,0 +1,11 @@
> >+RsaPrivKey ::= SEQUENCE {
> >+ version INTEGER,
> >+ n INTEGER ({ caam_rsa_get_n }),
> >+ e INTEGER ({ caam_rsa_get_e }),
> >+ d INTEGER ({ caam_rsa_get_d }),
> >+ prime1 INTEGER,
> >+ prime2 INTEGER,
> >+ exponent1 INTEGER,
> >+ exponent2 INTEGER,
> >+ coefficient INTEGER
> >+}
>
> Why do you define your own ASN.1 sequence? Why not using the common
> crypto/rsaprivkey.asn1?
>

[ta] The functions indicated in crypto/rsaprivkey.asn1 return the key members in MPI format. Our hardware expects the keys as u8 buffers; retrieving the key members in MPI format and then writing them to u8 buffers would be an unnecessary step.

> >diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
> >new file mode 100644
> >index 0000000..8dd5ff2
> >--- /dev/null
> >+++ b/drivers/crypto/caam/caampkc.c
> >@@ -0,0 +1,616 @@
> >+int caam_rsa_get_n(void *context, size_t hdrlen, unsigned char tag,
> >+ const void *value, size_t vlen)
>
> This function and the following functions are very similar to the ones in
> rsa_helper.c -- shouldn't those be used instead?
>

[ta] Those functions use the MPI lib and I don't need it.

> >+static void rsa_free_key(struct caam_pkc_context *ctx)
> >+{
> >+ kfree(ctx->n);
> >+ ctx->n = NULL;
> >+ kfree(ctx->e);
> >+ ctx->e = NULL;
> >+
> >+ if (ctx->d) {
> >+ memset(ctx->d, '\0', ctx->key_sz);
> >+ kfree(ctx->d);
>
> kzfree, please
>

Thanks,
ta

2016-02-27 17:08:31

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH 3/3] crypto: caam - add support for RSA algorithm

Tudor-Dan Ambarus <[email protected]> wrote:
> Hi Stephan,
>
>> -----Original Message-----
>> >+++ b/drivers/crypto/caam/caam_rsaprivkey.asn1
>> >@@ -0,0 +1,11 @@
>> >+RsaPrivKey ::= SEQUENCE {
>> >+ version INTEGER,
>> >+ n INTEGER ({ caam_rsa_get_n }),
>> >+ e INTEGER ({ caam_rsa_get_e }),
>> >+ d INTEGER ({ caam_rsa_get_d }),
>> >+ prime1 INTEGER,
>> >+ prime2 INTEGER,
>> >+ exponent1 INTEGER,
>> >+ exponent2 INTEGER,
>> >+ coefficient INTEGER
>> >+}
>>
>> Why do you define your own ASN.1 sequence? Why not using the common
>> crypto/rsaprivkey.asn1?
>>
>
> [ta] The functions indicated in crypto/rsaprivkey.asn1 return the key members in MPI format. Our hardware expects the keys as u8 buffers; retrieving the key members in MPI format and then writing them to u8 buffers would be an unnecessary step.

Is there any reason why we can't change it to return the raw
integer and make the software RSA implementation do the MPI parsing
instead?

As hardware RSA implementations are likely to want to use raw
integers we don't really want everyone to have their own parser.

I know qat has already gone in with its own parser but we should
fix it too.

Thanks,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

2016-03-01 11:45:20

by Tudor-Dan Ambarus

[permalink] [raw]
Subject: RE: [PATCH 3/3] crypto: caam - add support for RSA algorithm

Hi Herbert,

> >> -----Original Message-----
> >> >+++ b/drivers/crypto/caam/caam_rsaprivkey.asn1
> >> >@@ -0,0 +1,11 @@
> >> >+RsaPrivKey ::= SEQUENCE {
> >> >+ version INTEGER,
> >> >+ n INTEGER ({ caam_rsa_get_n }),
> >> >+ e INTEGER ({ caam_rsa_get_e }),
> >> >+ d INTEGER ({ caam_rsa_get_d }),
> >> >+ prime1 INTEGER,
> >> >+ prime2 INTEGER,
> >> >+ exponent1 INTEGER,
> >> >+ exponent2 INTEGER,
> >> >+ coefficient INTEGER
> >> >+}
> >>
> >> Why do you define your own ASN.1 sequence? Why not using the common
> >> crypto/rsaprivkey.asn1?
> >>
> >
> > [ta] The functions indicated in crypto/rsaprivkey.asn1 return the key
> members in MPI format. Our hardware expects the keys as u8 buffers;
> retrieving the key members in MPI format and then writing them to u8
> buffers would be an unnecessary step.
>
> Is there any reason why we can't change it to return the raw
> integer and make the software RSA implementation do the MPI parsing
> instead?

You will have a duplicate key allocation for the RSA software implementation.
One when returning the raw integer and the other when doing the MPI parsing.
Can we live with the duplicate allocation?

Thanks,
ta