* [PATCH 1/3] crypto: scatterwak - Add scatterwalk_sg_copychunks
@ 2016-02-22 9:16 Tudor Ambarus
2016-02-22 9:16 ` [PATCH 2/3] crypto: scatterwalk - export scatterwalk_pagedone Tudor Ambarus
2016-02-22 9:16 ` [PATCH 3/3] crypto: caam - add support for RSA algorithm Tudor Ambarus
0 siblings, 2 replies; 10+ messages in thread
From: Tudor Ambarus @ 2016-02-22 9:16 UTC (permalink / raw)
To: herbert
Cc: linux-crypto, cristian.stoica, horia.geanta, alexandru.porosanu,
Tudor Ambarus
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 <tudor-dan.ambarus@nxp.com>
---
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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/3] crypto: scatterwalk - export scatterwalk_pagedone
2016-02-22 9:16 [PATCH 1/3] crypto: scatterwak - Add scatterwalk_sg_copychunks Tudor Ambarus
@ 2016-02-22 9:16 ` Tudor Ambarus
2016-02-22 9:16 ` [PATCH 3/3] crypto: caam - add support for RSA algorithm Tudor Ambarus
1 sibling, 0 replies; 10+ messages in thread
From: Tudor Ambarus @ 2016-02-22 9:16 UTC (permalink / raw)
To: herbert
Cc: linux-crypto, cristian.stoica, horia.geanta, alexandru.porosanu,
Tudor Ambarus
Used in caam driver. Export the symbol since the caam driver
can be built as a module.
Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
---
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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/3] crypto: caam - add support for RSA algorithm
2016-02-22 9:16 [PATCH 1/3] crypto: scatterwak - Add scatterwalk_sg_copychunks Tudor Ambarus
2016-02-22 9:16 ` [PATCH 2/3] crypto: scatterwalk - export scatterwalk_pagedone Tudor Ambarus
@ 2016-02-22 9:16 ` Tudor Ambarus
2016-02-22 10:10 ` Stephan Mueller
1 sibling, 1 reply; 10+ messages in thread
From: Tudor Ambarus @ 2016-02-22 9:16 UTC (permalink / raw)
To: herbert
Cc: linux-crypto, cristian.stoica, horia.geanta, alexandru.porosanu,
Tudor Ambarus
Add RSA support to caam driver.
Coauthored-by: Yashpal Dutta <yashpal.dutta@freescale.com>
Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
---
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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] crypto: caam - add support for RSA algorithm
2016-02-22 9:16 ` [PATCH 3/3] crypto: caam - add support for RSA algorithm Tudor Ambarus
@ 2016-02-22 10:10 ` Stephan Mueller
2016-02-22 11:40 ` Tudor-Dan Ambarus
0 siblings, 1 reply; 10+ messages in thread
From: Stephan Mueller @ 2016-02-22 10:10 UTC (permalink / raw)
To: Tudor Ambarus
Cc: herbert, linux-crypto, cristian.stoica, horia.geanta,
alexandru.porosanu
Am Montag, 22. Februar 2016, 11:16:17 schrieb Tudor Ambarus:
Hi Tudor,
>Add RSA support to caam driver.
>
>Coauthored-by: Yashpal Dutta <yashpal.dutta@freescale.com>
>
>Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
>---
> 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
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH 3/3] crypto: caam - add support for RSA algorithm
2016-02-22 10:10 ` Stephan Mueller
@ 2016-02-22 11:40 ` Tudor-Dan Ambarus
2016-02-27 17:08 ` Herbert Xu
0 siblings, 1 reply; 10+ messages in thread
From: Tudor-Dan Ambarus @ 2016-02-22 11:40 UTC (permalink / raw)
To: Stephan Mueller
Cc: herbert@gondor.apana.org.au, linux-crypto@vger.kernel.org,
Cristian Stoica, Horia Ioan Geanta Neag, Alexandru Porosanu
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
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] crypto: caam - add support for RSA algorithm
2016-02-22 11:40 ` Tudor-Dan Ambarus
@ 2016-02-27 17:08 ` Herbert Xu
2016-03-01 11:29 ` Tudor-Dan Ambarus
0 siblings, 1 reply; 10+ messages in thread
From: Herbert Xu @ 2016-02-27 17:08 UTC (permalink / raw)
To: Tudor-Dan Ambarus
Cc: smueller, linux-crypto, cristian.stoica, horia.geanta,
alexandru.porosanu
Tudor-Dan Ambarus <tudor-dan.ambarus@nxp.com> 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 <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH 3/3] crypto: caam - add support for RSA algorithm
2016-02-27 17:08 ` Herbert Xu
@ 2016-03-01 11:29 ` Tudor-Dan Ambarus
0 siblings, 0 replies; 10+ messages in thread
From: Tudor-Dan Ambarus @ 2016-03-01 11:29 UTC (permalink / raw)
To: Herbert Xu
Cc: smueller@chronox.de, linux-crypto@vger.kernel.org,
Cristian Stoica, Horia Ioan Geanta Neag, Alexandru Porosanu
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
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 3/3] crypto: caam - add support for RSA algorithm
2016-05-12 15:06 [PATCH v5 0/3] " Tudor Ambarus
@ 2016-05-12 15:06 ` Tudor Ambarus
2016-05-12 19:20 ` Horia Ioan Geanta Neag
0 siblings, 1 reply; 10+ messages in thread
From: Tudor Ambarus @ 2016-05-12 15:06 UTC (permalink / raw)
To: herbert; +Cc: linux-crypto, Tudor Ambarus
Add RSA support to caam driver.
Coauthored-by: Yashpal Dutta <yashpal.dutta@freescale.com>
Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
---
drivers/crypto/caam/Kconfig | 12 ++
drivers/crypto/caam/Makefile | 4 +
drivers/crypto/caam/caampkc.c | 466 +++++++++++++++++++++++++++++++++++++++++
drivers/crypto/caam/caampkc.h | 94 +++++++++
drivers/crypto/caam/desc.h | 2 +
drivers/crypto/caam/pdb.h | 16 +-
drivers/crypto/caam/pkc_desc.c | 138 ++++++++++++
7 files changed, 731 insertions(+), 1 deletion(-)
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..44449ba 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -99,6 +99,18 @@ 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_RSA
+ 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..399ad55 100644
--- a/drivers/crypto/caam/Makefile
+++ b/drivers/crypto/caam/Makefile
@@ -5,11 +5,15 @@ ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y)
EXTRA_CFLAGS := -DDEBUG
endif
+ccflags-y += -I$(srctree)/crypto
+
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-y := caampkc.o pkc_desc.o
diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
new file mode 100644
index 0000000..34ffa87
--- /dev/null
+++ b/drivers/crypto/caam/caampkc.c
@@ -0,0 +1,466 @@
+/*
+ * 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 "compat.h"
+#include "caampkc.h"
+#include "sg_sw_sec4.h"
+#include "regs.h"
+#include "intern.h"
+#include "jr.h"
+#include "error.h"
+
+static void rsa_io_unmap(struct device *dev, struct rsa_edesc *edesc,
+ struct akcipher_request *req)
+{
+ 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_pub_unmap(struct device *dev, struct rsa_edesc *edesc,
+ struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *key = &ctx->key;
+ struct rsa_pub_desc *hw_desc = (struct rsa_pub_desc *)edesc->hw_desc;
+
+ dma_unmap_single(dev, hw_desc->n_dma, key->n_sz, DMA_TO_DEVICE);
+ dma_unmap_single(dev, hw_desc->e_dma, key->e_sz, 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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *key = &ctx->key;
+ struct rsa_priv_f1_desc *hw_desc =
+ (struct rsa_priv_f1_desc *)edesc->hw_desc;
+
+ dma_unmap_single(dev, hw_desc->n_dma, key->n_sz, DMA_TO_DEVICE);
+ dma_unmap_single(dev, hw_desc->d_dma, key->n_sz, 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);
+ rsa_io_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);
+ rsa_io_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_rsa_ctx *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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *key = &ctx->key;
+ struct device *jrdev = ctx->dev;
+ struct rsa_edesc *edesc = NULL;
+ size_t desclen = sizeof(struct rsa_pub_desc);
+ int ret;
+
+ if (unlikely(!key->n || !key->e))
+ return -EINVAL;
+
+ if (req->dst_len < key->n_sz) {
+ req->dst_len = key->n_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)
+ goto init_fail;
+
+ ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_pub_done, req);
+ if (!ret)
+ return -EINPROGRESS;
+
+ rsa_pub_unmap(jrdev, edesc, req);
+
+init_fail:
+ rsa_io_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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *key = &ctx->key;
+ struct device *jrdev = ctx->dev;
+ struct rsa_edesc *edesc = NULL;
+ size_t desclen = sizeof(struct rsa_priv_f1_desc);
+ int ret;
+
+ if (unlikely(!key->n || !key->d))
+ return -EINVAL;
+
+ if (req->dst_len < key->n_sz) {
+ req->dst_len = key->n_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)
+ goto init_fail;
+
+ ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_priv_f1_done, req);
+ if (!ret)
+ return -EINPROGRESS;
+
+ rsa_priv_f1_unmap(jrdev, edesc, req);
+
+init_fail:
+ rsa_io_unmap(jrdev, edesc, req);
+ kfree(edesc);
+ return ret;
+}
+
+static int caam_rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key,
+ unsigned int keylen)
+{
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *rsa_key = &ctx->key;
+
+ return rsa_parse_pub_key(rsa_key, key, keylen);
+}
+
+static int caam_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
+ unsigned int keylen)
+{
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *rsa_key = &ctx->key;
+
+ return rsa_parse_priv_key(rsa_key, key, keylen);
+}
+
+static int caam_rsa_max_size(struct crypto_akcipher *tfm)
+{
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *key = &ctx->key;
+
+ return (key->n) ? key->n_sz : -EINVAL;
+}
+
+/* Per session pkc's driver context creation function */
+static int caam_rsa_init_tfm(struct crypto_akcipher *tfm)
+{
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *key = &ctx->key;
+
+ 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);
+ }
+
+ key->flags = GFP_DMA | GFP_KERNEL;
+ return 0;
+}
+
+/* Per session pkc's driver context cleanup function */
+static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm)
+{
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *key = &ctx->key;
+
+ rsa_free_key(key);
+ caam_jr_free(ctx->dev);
+}
+
+static struct akcipher_alg caam_rsa = {
+ .encrypt = caam_rsa_enc,
+ .decrypt = caam_rsa_dec,
+ .sign = caam_rsa_dec,
+ .verify = caam_rsa_enc,
+ .set_pub_key = caam_rsa_set_pub_key,
+ .set_priv_key = caam_rsa_set_priv_key,
+ .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_rsa_ctx),
+ },
+};
+
+/* 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;
+
+ caam_rsa.base.cra_flags = 0;
+ err = crypto_register_akcipher(&caam_rsa);
+ if (err)
+ dev_warn(ctrldev, "%s alg registration failed\n",
+ caam_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(&caam_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..398a881
--- /dev/null
+++ b/drivers/crypto/caam/caampkc.h
@@ -0,0 +1,94 @@
+/*
+ * 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/internal/rsa.h>
+#include <crypto/akcipher.h>
+#include <crypto/internal/akcipher.h>
+#include "desc_constr.h"
+#include "pdb.h"
+#include "rsapubkey-asn1.h"
+#include "rsaprivkey-asn1.h"
+
+/**
+ * caam_rsa_ctx - per session context.
+ * @key: RSA key structure
+ * @dev: device structure
+ */
+struct caam_rsa_ctx {
+ struct rsa_key key;
+ struct device *dev;
+};
+
+/**
+ * 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..25c0690
--- /dev/null
+++ b/drivers/crypto/caam/pkc_desc.c
@@ -0,0 +1,138 @@
+/*
+ * 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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *key = &ctx->key;
+ 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, key->n, key->n_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, key->e, key->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 |= (key->e_sz << RSA_PDB_E_SHIFT) | key->n_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, key->n_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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *key = &ctx->key;
+ 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, key->n, key->n_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, key->d, key->n_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 |= (key->n_sz << RSA_PDB_D_SHIFT) | key->n_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, key->n_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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 3/3] crypto: caam - add support for RSA algorithm
2016-05-12 15:06 ` [PATCH 3/3] " Tudor Ambarus
@ 2016-05-12 19:20 ` Horia Ioan Geanta Neag
0 siblings, 0 replies; 10+ messages in thread
From: Horia Ioan Geanta Neag @ 2016-05-12 19:20 UTC (permalink / raw)
To: Tudor-Dan Ambarus, herbert@gondor.apana.org.au
Cc: linux-crypto@vger.kernel.org
On 5/12/2016 6:06 PM, Tudor Ambarus wrote:
> Add RSA support to caam driver.
>
> Coauthored-by: Yashpal Dutta <yashpal.dutta@freescale.com>
>
> Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
> ---
> drivers/crypto/caam/Kconfig | 12 ++
> drivers/crypto/caam/Makefile | 4 +
> drivers/crypto/caam/caampkc.c | 466 +++++++++++++++++++++++++++++++++++++++++
> drivers/crypto/caam/caampkc.h | 94 +++++++++
> drivers/crypto/caam/desc.h | 2 +
> drivers/crypto/caam/pdb.h | 16 +-
> drivers/crypto/caam/pkc_desc.c | 138 ++++++++++++
> 7 files changed, 731 insertions(+), 1 deletion(-)
> 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..44449ba 100644
> --- a/drivers/crypto/caam/Kconfig
> +++ b/drivers/crypto/caam/Kconfig
> @@ -99,6 +99,18 @@ 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_RSA
> + 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..399ad55 100644
> --- a/drivers/crypto/caam/Makefile
> +++ b/drivers/crypto/caam/Makefile
> @@ -5,11 +5,15 @@ ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y)
> EXTRA_CFLAGS := -DDEBUG
> endif
>
> +ccflags-y += -I$(srctree)/crypto
> +
> 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-y := caampkc.o pkc_desc.o
> diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
> new file mode 100644
> index 0000000..34ffa87
> --- /dev/null
> +++ b/drivers/crypto/caam/caampkc.c
> @@ -0,0 +1,466 @@
> +/*
> + * 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 "compat.h"
> +#include "caampkc.h"
> +#include "sg_sw_sec4.h"
> +#include "regs.h"
> +#include "intern.h"
> +#include "jr.h"
> +#include "error.h"
> +
> +static void rsa_io_unmap(struct device *dev, struct rsa_edesc *edesc,
> + struct akcipher_request *req)
> +{
> + 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_pub_unmap(struct device *dev, struct rsa_edesc *edesc,
> + struct akcipher_request *req)
> +{
> + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
> + struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *key = &ctx->key;
> + struct rsa_pub_desc *hw_desc = (struct rsa_pub_desc *)edesc->hw_desc;
> +
> + dma_unmap_single(dev, hw_desc->n_dma, key->n_sz, DMA_TO_DEVICE);
> + dma_unmap_single(dev, hw_desc->e_dma, key->e_sz, 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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *key = &ctx->key;
> + struct rsa_priv_f1_desc *hw_desc =
> + (struct rsa_priv_f1_desc *)edesc->hw_desc;
> +
> + dma_unmap_single(dev, hw_desc->n_dma, key->n_sz, DMA_TO_DEVICE);
> + dma_unmap_single(dev, hw_desc->d_dma, key->n_sz, 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);
> + rsa_io_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);
> + rsa_io_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_rsa_ctx *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);
Where is sec4_sg_dma unmapped?
> + 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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *key = &ctx->key;
> + struct device *jrdev = ctx->dev;
> + struct rsa_edesc *edesc = NULL;
> + size_t desclen = sizeof(struct rsa_pub_desc);
> + int ret;
> +
> + if (unlikely(!key->n || !key->e))
> + return -EINVAL;
> +
> + if (req->dst_len < key->n_sz) {
> + req->dst_len = key->n_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)
> + goto init_fail;
> +
> + ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_pub_done, req);
> + if (!ret)
> + return -EINPROGRESS;
> +
> + rsa_pub_unmap(jrdev, edesc, req);
> +
> +init_fail:
> + rsa_io_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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *key = &ctx->key;
> + struct device *jrdev = ctx->dev;
> + struct rsa_edesc *edesc = NULL;
> + size_t desclen = sizeof(struct rsa_priv_f1_desc);
> + int ret;
> +
> + if (unlikely(!key->n || !key->d))
> + return -EINVAL;
> +
> + if (req->dst_len < key->n_sz) {
> + req->dst_len = key->n_sz;
Be consistent with caam_rsa_enc(): either do a dev_err() here, or remove
the error message in caam_rsa_enc().
> + 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)
> + goto init_fail;
> +
> + ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_priv_f1_done, req);
> + if (!ret)
> + return -EINPROGRESS;
> +
> + rsa_priv_f1_unmap(jrdev, edesc, req);
> +
> +init_fail:
> + rsa_io_unmap(jrdev, edesc, req);
> + kfree(edesc);
> + return ret;
> +}
> +
> +static int caam_rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key,
> + unsigned int keylen)
> +{
> + struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *rsa_key = &ctx->key;
> +
> + return rsa_parse_pub_key(rsa_key, key, keylen);
> +}
> +
> +static int caam_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
> + unsigned int keylen)
> +{
> + struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *rsa_key = &ctx->key;
> +
> + return rsa_parse_priv_key(rsa_key, key, keylen);
> +}
> +
> +static int caam_rsa_max_size(struct crypto_akcipher *tfm)
> +{
> + struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *key = &ctx->key;
> +
> + return (key->n) ? key->n_sz : -EINVAL;
> +}
> +
> +/* Per session pkc's driver context creation function */
> +static int caam_rsa_init_tfm(struct crypto_akcipher *tfm)
> +{
> + struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *key = &ctx->key;
> +
> + 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);
> + }
> +
> + key->flags = GFP_DMA | GFP_KERNEL;
> + return 0;
> +}
> +
> +/* Per session pkc's driver context cleanup function */
> +static void caam_rsa_exit_tfm(struct crypto_akcipher *tfm)
> +{
> + struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *key = &ctx->key;
> +
> + rsa_free_key(key);
> + caam_jr_free(ctx->dev);
> +}
> +
> +static struct akcipher_alg caam_rsa = {
> + .encrypt = caam_rsa_enc,
> + .decrypt = caam_rsa_dec,
> + .sign = caam_rsa_dec,
> + .verify = caam_rsa_enc,
> + .set_pub_key = caam_rsa_set_pub_key,
> + .set_priv_key = caam_rsa_set_priv_key,
> + .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_rsa_ctx),
> + },
> +};
> +
> +/* 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;
> +
> + caam_rsa.base.cra_flags = 0;
> + err = crypto_register_akcipher(&caam_rsa);
> + if (err)
> + dev_warn(ctrldev, "%s alg registration failed\n",
> + caam_rsa.base.cra_driver_name);
> + else
> + dev_info(ctrldev, "caam algorithms registered in /proc/crypto\n");
Be specific which type of algorithms are being registered (pkc / asym).
> +
> + return err;
> +}
> +
> +static void __exit caam_pkc_exit(void)
> +{
> + crypto_unregister_akcipher(&caam_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..398a881
> --- /dev/null
> +++ b/drivers/crypto/caam/caampkc.h
> @@ -0,0 +1,94 @@
> +/*
> + * 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/internal/rsa.h>
> +#include <crypto/akcipher.h>
> +#include <crypto/internal/akcipher.h>
> +#include "desc_constr.h"
> +#include "pdb.h"
> +#include "rsapubkey-asn1.h"
> +#include "rsaprivkey-asn1.h"
> +
> +/**
> + * caam_rsa_ctx - per session context.
> + * @key: RSA key structure
> + * @dev: device structure
> + */
> +struct caam_rsa_ctx {
> + struct rsa_key key;
> + struct device *dev;
> +};
> +
> +/**
> + * 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
s/ecrypted/encrypted
> + * @n_dma: dma address of RSA public exponent
modulus
> + * @dma_e: dma address of RSA public exponent
s/dma_e/e_dma
> + * @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
s/ecrypted/encrypted
> + * @f_dma: dma address of output data
> + * @n_dma: dma address of RSA public exponent
modulus
> + * @dma_d: dma address of RSA private exponent
s/dma_d/d_dma
> + * @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..25c0690
> --- /dev/null
> +++ b/drivers/crypto/caam/pkc_desc.c
> @@ -0,0 +1,138 @@
> +/*
> + * 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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *key = &ctx->key;
> + 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, key->n, key->n_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, key->e, key->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;
Descriptor has a few addresses in it, thus you'll also have to use
CAAM_PTR_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 |= (key->e_sz << RSA_PDB_E_SHIFT) | key->n_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, key->n_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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
> + struct rsa_key *key = &ctx->key;
> + 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, key->n, key->n_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, key->d, key->n_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;
Descriptor has a few addresses in it, thus you'll also have to use
CAAM_PTR_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 |= (key->n_sz << RSA_PDB_D_SHIFT) | key->n_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, key->n_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;
> +}
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 3/3] crypto: caam - add support for RSA algorithm
2016-06-07 14:24 [PATCH v7 0/3] " Tudor Ambarus
@ 2016-06-07 14:24 ` Tudor Ambarus
0 siblings, 0 replies; 10+ messages in thread
From: Tudor Ambarus @ 2016-06-07 14:24 UTC (permalink / raw)
To: herbert; +Cc: linux-crypto, horia.geanta, Tudor Ambarus
Add RSA support to caam driver.
Coauthored-by: Yashpal Dutta <yashpal.dutta@freescale.com>
Signed-off-by: Tudor Ambarus <tudor-dan.ambarus@nxp.com>
---
drivers/crypto/caam/Kconfig | 12 +
drivers/crypto/caam/Makefile | 4 +
drivers/crypto/caam/caampkc.c | 637 ++++++++++++++++++++++++++++++++++++++
drivers/crypto/caam/caampkc.h | 72 +++++
drivers/crypto/caam/compat.h | 3 +
drivers/crypto/caam/desc.h | 2 +
drivers/crypto/caam/desc_constr.h | 7 +
drivers/crypto/caam/pdb.h | 51 ++-
drivers/crypto/caam/pkc_desc.c | 36 +++
9 files changed, 823 insertions(+), 1 deletion(-)
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..44449ba 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -99,6 +99,18 @@ 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_RSA
+ 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..399ad55 100644
--- a/drivers/crypto/caam/Makefile
+++ b/drivers/crypto/caam/Makefile
@@ -5,11 +5,15 @@ ifeq ($(CONFIG_CRYPTO_DEV_FSL_CAAM_DEBUG), y)
EXTRA_CFLAGS := -DDEBUG
endif
+ccflags-y += -I$(srctree)/crypto
+
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-y := caampkc.o pkc_desc.o
diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c
new file mode 100644
index 0000000..38a004d
--- /dev/null
+++ b/drivers/crypto/caam/caampkc.c
@@ -0,0 +1,637 @@
+/*
+ * 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 "compat.h"
+#include "regs.h"
+#include "intern.h"
+#include "jr.h"
+#include "error.h"
+#include "desc_constr.h"
+#include "sg_sw_sec4.h"
+#include "caampkc.h"
+#include "rsapubkey-asn1.h"
+#include "rsaprivkey-asn1.h"
+
+#define DESC_RSA_PUB_LEN (2 * CAAM_CMD_SZ + sizeof(struct rsa_pub_pdb))
+#define DESC_RSA_PRIV_F1_LEN (2 * CAAM_CMD_SZ + \
+ sizeof(struct rsa_priv_f1_pdb))
+
+static void rsa_io_unmap(struct device *dev, struct rsa_edesc *edesc,
+ struct akcipher_request *req)
+{
+ dma_unmap_sg(dev, req->dst, edesc->dst_nents, DMA_FROM_DEVICE);
+ dma_unmap_sg(dev, req->src, edesc->src_nents, DMA_TO_DEVICE);
+
+ if (edesc->sec4_sg_bytes)
+ dma_unmap_single(dev, edesc->sec4_sg_dma, edesc->sec4_sg_bytes,
+ DMA_TO_DEVICE);
+}
+
+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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct caam_rsa_key *key = &ctx->key;
+ struct rsa_pub_pdb *pdb = &edesc->pdb.pub;
+
+ dma_unmap_single(dev, pdb->n_dma, key->n_sz, DMA_TO_DEVICE);
+ dma_unmap_single(dev, pdb->e_dma, key->e_sz, 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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct caam_rsa_key *key = &ctx->key;
+ struct rsa_priv_f1_pdb *pdb = &edesc->pdb.priv_f1;
+
+ dma_unmap_single(dev, pdb->n_dma, key->n_sz, DMA_TO_DEVICE);
+ dma_unmap_single(dev, pdb->d_dma, key->n_sz, 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);
+ rsa_io_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);
+ rsa_io_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_rsa_ctx *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;
+ }
+
+ edesc->sec4_sg_bytes = sec4_sg_bytes;
+
+ 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 set_rsa_pub_pdb(struct akcipher_request *req,
+ struct rsa_edesc *edesc)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct caam_rsa_key *key = &ctx->key;
+ struct device *dev = ctx->dev;
+ struct rsa_pub_pdb *pdb = &edesc->pdb.pub;
+ int sec4_sg_index = 0;
+
+ pdb->n_dma = dma_map_single(dev, key->n, key->n_sz, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, pdb->n_dma)) {
+ dev_err(dev, "Unable to map RSA modulus memory\n");
+ return -ENOMEM;
+ }
+
+ pdb->e_dma = dma_map_single(dev, key->e, key->e_sz, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, pdb->e_dma)) {
+ dev_err(dev, "Unable to map RSA public exponent memory\n");
+ dma_unmap_single(dev, pdb->n_dma, key->n_sz, DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+
+ if (edesc->src_nents > 1) {
+ pdb->sgf |= RSA_PDB_SGF_F;
+ pdb->f_dma = edesc->sec4_sg_dma;
+ sec4_sg_index += edesc->src_nents;
+ } else {
+ pdb->f_dma = sg_dma_address(req->src);
+ }
+
+ if (edesc->dst_nents > 1) {
+ pdb->sgf |= RSA_PDB_SGF_G;
+ pdb->g_dma = edesc->sec4_sg_dma +
+ sec4_sg_index * sizeof(struct sec4_sg_entry);
+ } else {
+ pdb->g_dma = sg_dma_address(req->dst);
+ }
+
+ pdb->sgf |= (key->e_sz << RSA_PDB_E_SHIFT) | key->n_sz;
+ pdb->f_len = req->src_len;
+
+ return 0;
+}
+
+static int set_rsa_priv_f1_pdb(struct akcipher_request *req,
+ struct rsa_edesc *edesc)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct caam_rsa_key *key = &ctx->key;
+ struct device *dev = ctx->dev;
+ struct rsa_priv_f1_pdb *pdb = &edesc->pdb.priv_f1;
+ int sec4_sg_index = 0;
+
+ pdb->n_dma = dma_map_single(dev, key->n, key->n_sz, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, pdb->n_dma)) {
+ dev_err(dev, "Unable to map modulus memory\n");
+ return -ENOMEM;
+ }
+
+ pdb->d_dma = dma_map_single(dev, key->d, key->n_sz, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, pdb->d_dma)) {
+ dev_err(dev, "Unable to map RSA private exponent memory\n");
+ dma_unmap_single(dev, pdb->n_dma, key->n_sz, DMA_TO_DEVICE);
+ return -ENOMEM;
+ }
+
+ if (edesc->src_nents > 1) {
+ pdb->sgf |= RSA_PRIV_PDB_SGF_G;
+ pdb->g_dma = edesc->sec4_sg_dma;
+ sec4_sg_index += edesc->src_nents;
+ } else {
+ pdb->g_dma = sg_dma_address(req->src);
+ }
+
+ if (edesc->dst_nents > 1) {
+ pdb->sgf |= RSA_PRIV_PDB_SGF_F;
+ pdb->f_dma = edesc->sec4_sg_dma +
+ sec4_sg_index * sizeof(struct sec4_sg_entry);
+ } else {
+ pdb->f_dma = sg_dma_address(req->dst);
+ }
+
+ pdb->sgf |= (key->n_sz << RSA_PDB_D_SHIFT) | key->n_sz;
+
+ return 0;
+}
+
+static int caam_rsa_enc(struct akcipher_request *req)
+{
+ struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req);
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct caam_rsa_key *key = &ctx->key;
+ struct device *jrdev = ctx->dev;
+ struct rsa_edesc *edesc;
+ int ret;
+
+ if (unlikely(!key->n || !key->e))
+ return -EINVAL;
+
+ if (req->dst_len < key->n_sz) {
+ req->dst_len = key->n_sz;
+ dev_err(jrdev, "Output buffer length less than parameter n\n");
+ return -EOVERFLOW;
+ }
+
+ /* Allocate extended descriptor */
+ edesc = rsa_edesc_alloc(req, DESC_RSA_PUB_LEN);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ /* Set RSA Encrypt Protocol Data Block */
+ ret = set_rsa_pub_pdb(req, edesc);
+ if (ret)
+ goto init_fail;
+
+ /* Initialize Job Descriptor */
+ init_rsa_pub_desc(edesc->hw_desc, &edesc->pdb.pub);
+
+ ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_pub_done, req);
+ if (!ret)
+ return -EINPROGRESS;
+
+ rsa_pub_unmap(jrdev, edesc, req);
+
+init_fail:
+ rsa_io_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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct caam_rsa_key *key = &ctx->key;
+ struct device *jrdev = ctx->dev;
+ struct rsa_edesc *edesc;
+ int ret;
+
+ if (unlikely(!key->n || !key->d))
+ return -EINVAL;
+
+ if (req->dst_len < key->n_sz) {
+ req->dst_len = key->n_sz;
+ dev_err(jrdev, "Output buffer length less than parameter n\n");
+ return -EOVERFLOW;
+ }
+
+ /* Allocate extended descriptor */
+ edesc = rsa_edesc_alloc(req, DESC_RSA_PRIV_F1_LEN);
+ if (IS_ERR(edesc))
+ return PTR_ERR(edesc);
+
+ /* Set RSA Decrypt Protocol Data Block - Private Key Form #1 */
+ ret = set_rsa_priv_f1_pdb(req, edesc);
+ if (ret)
+ goto init_fail;
+
+ /* Initialize Job Descriptor */
+ init_rsa_priv_f1_desc(edesc->hw_desc, &edesc->pdb.priv_f1);
+
+ ret = caam_jr_enqueue(jrdev, edesc->hw_desc, rsa_priv_f1_done, req);
+ if (!ret)
+ return -EINPROGRESS;
+
+ rsa_priv_f1_unmap(jrdev, edesc, req);
+
+init_fail:
+ rsa_io_unmap(jrdev, edesc, req);
+ kfree(edesc);
+ return ret;
+}
+
+static void caam_rsa_free_key(struct caam_rsa_key *key)
+{
+ kzfree(key->d);
+ kfree(key->e);
+ kfree(key->n);
+ key->d = NULL;
+ key->e = NULL;
+ key->n = NULL;
+ key->d_sz = 0;
+ key->e_sz = 0;
+ key->n_sz = 0;
+}
+
+static int caam_rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key,
+ unsigned int keylen)
+{
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *raw_key = &ctx->raw_key;
+ struct caam_rsa_key *rsa_key = &ctx->key;
+ int ret;
+
+ /* Free the old RSA key if any */
+ caam_rsa_free_key(rsa_key);
+
+ ret = rsa_parse_pub_key(raw_key, key, keylen);
+ if (ret)
+ return ret;
+
+ /* Copy key in DMA zone */
+ rsa_key->e = kzalloc(raw_key->e_sz, GFP_DMA | GFP_KERNEL);
+ if (!rsa_key->e)
+ goto err;
+
+ rsa_key->n = kzalloc(raw_key->n_sz, GFP_DMA | GFP_KERNEL);
+ if (!rsa_key->n)
+ goto err;
+
+ rsa_key->e_sz = raw_key->e_sz;
+ rsa_key->n_sz = raw_key->n_sz;
+ memcpy(rsa_key->e, raw_key->e, raw_key->e_sz);
+ memcpy(rsa_key->n, raw_key->n, raw_key->n_sz);
+
+ return 0;
+err:
+ caam_rsa_free_key(rsa_key);
+ return -ENOMEM;
+}
+
+static int caam_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key,
+ unsigned int keylen)
+{
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct rsa_key *raw_key = &ctx->raw_key;
+ struct caam_rsa_key *rsa_key = &ctx->key;
+ int ret;
+
+ /* Free the old RSA key if any */
+ caam_rsa_free_key(rsa_key);
+
+ ret = rsa_parse_priv_key(raw_key, key, keylen);
+ if (ret)
+ return ret;
+
+ /* Copy key in DMA zone */
+ rsa_key->d = kzalloc(raw_key->d_sz, GFP_DMA | GFP_KERNEL);
+ if (!rsa_key->d)
+ goto err;
+
+ rsa_key->e = kzalloc(raw_key->e_sz, GFP_DMA | GFP_KERNEL);
+ if (!rsa_key->e)
+ goto err;
+
+ rsa_key->n = kzalloc(raw_key->n_sz, GFP_DMA | GFP_KERNEL);
+ if (!rsa_key->n)
+ goto err;
+
+ rsa_key->d_sz = raw_key->d_sz;
+ rsa_key->e_sz = raw_key->e_sz;
+ rsa_key->n_sz = raw_key->n_sz;
+ memcpy(rsa_key->d, raw_key->d, raw_key->d_sz);
+ memcpy(rsa_key->e, raw_key->e, raw_key->e_sz);
+ memcpy(rsa_key->n, raw_key->n, raw_key->n_sz);
+
+ return 0;
+
+err:
+ caam_rsa_free_key(rsa_key);
+ return -ENOMEM;
+}
+
+static int caam_rsa_max_size(struct crypto_akcipher *tfm)
+{
+ struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct caam_rsa_key *key = &ctx->key;
+
+ return (key->n) ? key->n_sz : -EINVAL;
+}
+
+/* Per session pkc's driver context creation function */
+static int caam_rsa_init_tfm(struct crypto_akcipher *tfm)
+{
+ struct caam_rsa_ctx *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_rsa_ctx *ctx = akcipher_tfm_ctx(tfm);
+ struct caam_rsa_key *key = &ctx->key;
+
+ caam_rsa_free_key(key);
+ caam_jr_free(ctx->dev);
+}
+
+static struct akcipher_alg caam_rsa = {
+ .encrypt = caam_rsa_enc,
+ .decrypt = caam_rsa_dec,
+ .sign = caam_rsa_dec,
+ .verify = caam_rsa_enc,
+ .set_pub_key = caam_rsa_set_pub_key,
+ .set_priv_key = caam_rsa_set_priv_key,
+ .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_ctxsize = sizeof(struct caam_rsa_ctx),
+ },
+};
+
+/* 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;
+
+ 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;
+
+ err = crypto_register_akcipher(&caam_rsa);
+ if (err)
+ dev_warn(ctrldev, "%s alg registration failed\n",
+ caam_rsa.base.cra_driver_name);
+ else
+ dev_info(ctrldev, "caam pkc algorithms registered in /proc/crypto\n");
+
+ return err;
+}
+
+static void __exit caam_pkc_exit(void)
+{
+ crypto_unregister_akcipher(&caam_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..a9bed48
--- /dev/null
+++ b/drivers/crypto/caam/caampkc.h
@@ -0,0 +1,72 @@
+/*
+ * 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 "compat.h"
+#include "pdb.h"
+
+/**
+ * caam_rsa_key - CAAM RSA key structure. Keys are allocated in DMA zone.
+ * @n : RSA modulus raw byte stream
+ * @e : RSA public exponent raw byte stream
+ * @d : RSA private exponent raw byte stream
+ * @n_sz : length in bytes of RSA modulus n
+ * @e_sz : length in bytes of RSA public exponent
+ * @d_sz : length in bytes of RSA private exponent
+ */
+struct caam_rsa_key {
+ u8 *n;
+ u8 *e;
+ u8 *d;
+ size_t n_sz;
+ size_t e_sz;
+ size_t d_sz;
+};
+
+/**
+ * caam_rsa_ctx - per session context.
+ * @raw_key : raw RSA key parsed by the ASN.1 decoder
+ * @key : CAAM RSA key in DMA zone
+ * @dev : device structure
+ */
+struct caam_rsa_ctx {
+ struct rsa_key raw_key;
+ struct caam_rsa_key key;
+ struct device *dev;
+};
+
+/**
+ * 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_bytes : length of h/w link table
+ * @sec4_sg_dma : dma address of h/w link table
+ * @sec4_sg : pointer to h/w link table
+ * @pdb : specific RSA Protocol Data Block (PDB)
+ * @hw_desc : descriptor followed by link tables if any
+ */
+struct rsa_edesc {
+ int src_nents;
+ int dst_nents;
+ int sec4_sg_bytes;
+ dma_addr_t sec4_sg_dma;
+ struct sec4_sg_entry *sec4_sg;
+ union {
+ struct rsa_pub_pdb pub;
+ struct rsa_priv_f1_pdb priv_f1;
+ } pdb;
+ u32 hw_desc[];
+};
+
+/* Descriptor construction primitives. */
+void init_rsa_pub_desc(u32 *desc, struct rsa_pub_pdb *pdb);
+void init_rsa_priv_f1_desc(u32 *desc, struct rsa_priv_f1_pdb *pdb);
+
+#endif
diff --git a/drivers/crypto/caam/compat.h b/drivers/crypto/caam/compat.h
index b6955ec..7149cd2 100644
--- a/drivers/crypto/caam/compat.h
+++ b/drivers/crypto/caam/compat.h
@@ -35,8 +35,11 @@
#include <crypto/md5.h>
#include <crypto/internal/aead.h>
#include <crypto/authenc.h>
+#include <crypto/akcipher.h>
#include <crypto/scatterwalk.h>
#include <crypto/internal/skcipher.h>
#include <crypto/internal/hash.h>
+#include <crypto/internal/rsa.h>
+#include <crypto/internal/akcipher.h>
#endif /* !defined(CAAM_COMPAT_H) */
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/desc_constr.h b/drivers/crypto/caam/desc_constr.h
index 98d07de..3ff47b9 100644
--- a/drivers/crypto/caam/desc_constr.h
+++ b/drivers/crypto/caam/desc_constr.h
@@ -74,6 +74,13 @@ static inline void init_job_desc(u32 *desc, u32 options)
init_desc(desc, CMD_DESC_HDR | options);
}
+static inline void init_job_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes)
+{
+ u32 pdb_len = (pdb_bytes + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ;
+
+ init_job_desc(desc, (((pdb_len + 1) << HDR_START_IDX_SHIFT)) | options);
+}
+
static inline void append_ptr(u32 *desc, dma_addr_t ptr)
{
dma_addr_t *offset = (dma_addr_t *)desc_end(desc);
diff --git a/drivers/crypto/caam/pdb.h b/drivers/crypto/caam/pdb.h
index 3a87c0c..d0a5db2 100644
--- a/drivers/crypto/caam/pdb.h
+++ b/drivers/crypto/caam/pdb.h
@@ -1,12 +1,13 @@
/*
* CAAM Protocol Data Block (PDB) definition header file
*
- * Copyright 2008-2012 Freescale Semiconductor, Inc.
+ * Copyright 2008-2016 Freescale Semiconductor, Inc.
*
*/
#ifndef CAAM_PDB_H
#define CAAM_PDB_H
+#include "compat.h"
/*
* PDB- IPSec ESP Header Modification Options
@@ -399,4 +400,52 @@ 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
+
+/**
+ * RSA Encrypt Protocol Data Block
+ * @sgf: scatter-gather field
+ * @f_dma: dma address of input data
+ * @g_dma: dma address of encrypted output data
+ * @n_dma: dma address of RSA modulus
+ * @e_dma: dma address of RSA public exponent
+ * @f_len: length in octets of the input data
+ */
+struct rsa_pub_pdb {
+ 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;
+} __packed;
+
+/**
+ * RSA Decrypt PDB - Private Key Form #1
+ * @sgf: scatter-gather field
+ * @g_dma: dma address of encrypted input data
+ * @f_dma: dma address of output data
+ * @n_dma: dma address of RSA modulus
+ * @d_dma: dma address of RSA private exponent
+ */
+struct rsa_priv_f1_pdb {
+ u32 sgf;
+ dma_addr_t g_dma;
+ dma_addr_t f_dma;
+ dma_addr_t n_dma;
+ dma_addr_t d_dma;
+} __packed;
+
#endif
diff --git a/drivers/crypto/caam/pkc_desc.c b/drivers/crypto/caam/pkc_desc.c
new file mode 100644
index 0000000..4e4183e
--- /dev/null
+++ b/drivers/crypto/caam/pkc_desc.c
@@ -0,0 +1,36 @@
+/*
+ * 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"
+#include "desc_constr.h"
+
+/* Descriptor for RSA Public operation */
+void init_rsa_pub_desc(u32 *desc, struct rsa_pub_pdb *pdb)
+{
+ init_job_desc_pdb(desc, 0, sizeof(*pdb));
+ append_cmd(desc, pdb->sgf);
+ append_ptr(desc, pdb->f_dma);
+ append_ptr(desc, pdb->g_dma);
+ append_ptr(desc, pdb->n_dma);
+ append_ptr(desc, pdb->e_dma);
+ append_cmd(desc, pdb->f_len);
+ append_operation(desc, OP_TYPE_UNI_PROTOCOL | OP_PCLID_RSAENC_PUBKEY);
+}
+
+/* Descriptor for RSA Private operation - Private Key Form #1 */
+void init_rsa_priv_f1_desc(u32 *desc, struct rsa_priv_f1_pdb *pdb)
+{
+ init_job_desc_pdb(desc, 0, sizeof(*pdb));
+ append_cmd(desc, pdb->sgf);
+ append_ptr(desc, pdb->g_dma);
+ append_ptr(desc, pdb->f_dma);
+ append_ptr(desc, pdb->n_dma);
+ append_ptr(desc, pdb->d_dma);
+ append_operation(desc, OP_TYPE_UNI_PROTOCOL | OP_PCLID_RSADEC_PRVKEY |
+ RSA_PRIV_KEY_FRM_1);
+}
--
1.8.3.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
end of thread, other threads:[~2016-06-07 14:24 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-02-22 9:16 [PATCH 1/3] crypto: scatterwak - Add scatterwalk_sg_copychunks Tudor Ambarus
2016-02-22 9:16 ` [PATCH 2/3] crypto: scatterwalk - export scatterwalk_pagedone Tudor Ambarus
2016-02-22 9:16 ` [PATCH 3/3] crypto: caam - add support for RSA algorithm Tudor Ambarus
2016-02-22 10:10 ` Stephan Mueller
2016-02-22 11:40 ` Tudor-Dan Ambarus
2016-02-27 17:08 ` Herbert Xu
2016-03-01 11:29 ` Tudor-Dan Ambarus
-- strict thread matches above, loose matches on Subject: below --
2016-05-12 15:06 [PATCH v5 0/3] " Tudor Ambarus
2016-05-12 15:06 ` [PATCH 3/3] " Tudor Ambarus
2016-05-12 19:20 ` Horia Ioan Geanta Neag
2016-06-07 14:24 [PATCH v7 0/3] " Tudor Ambarus
2016-06-07 14:24 ` [PATCH 3/3] " Tudor Ambarus
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox