2019-12-03 16:24:38

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v5 0/4] enable CAAM's HWRNG as default

Everyone:

This series is a continuation of original [discussion]. I don't know
if what's in the series is enough to use CAAMs HWRNG system wide, but
I am hoping that with enough iterations and feedback it will be.

Changes since [v1]:

- Original hw_random replaced with the one using output of TRNG directly

- SEC4 DRNG IP block exposed via crypto API

- Small fix regarding use of GFP_DMA added to the series

Chagnes since [v2]:

- msleep in polling loop to avoid wasting CPU cycles

- caam_trng_read() bails out early if 'wait' is set to 'false'

- fixed typo in ZII's name

Changes since [v3]:

- DRNG's .cra_name is now "stdrng"

- collected Reviewd-by tag from Lucas

- typo fixes in commit messages of the series

Changes since [v4]:

- Dropped "crypto: caam - RNG4 TRNG errata" and "crypto: caam -
enable prediction resistance in HRWNG" to limit the scope of the
series. Those two patches are not yet ready and can be submitted
separately later.

- Collected Tested-by from Chris

Feedback is welcome!

Thanks,
Andrey Smirnov

[discussion] https://patchwork.kernel.org/patch/9850669/
[v1] https://lore.kernel.org/lkml/[email protected]
[v2] https://lore.kernel.org/lkml/[email protected]
[v3] https://lore.kernel.org/lkml/[email protected]
[v4] https://lore.kernel.org/lkml/[email protected]

Andrey Smirnov (4):
crypto: caam - allocate RNG instantiation descriptor with GFP_DMA
crypto: caam - move RNG presence check into a shared function
crypto: caam - replace DRNG with TRNG for use with hw_random
crypto: caam - expose SEC4 DRNG via crypto RNG API

drivers/crypto/caam/Kconfig | 15 +-
drivers/crypto/caam/Makefile | 3 +-
drivers/crypto/caam/caamrng.c | 358 ----------------------------------
drivers/crypto/caam/ctrl.c | 10 +-
drivers/crypto/caam/drng.c | 174 +++++++++++++++++
drivers/crypto/caam/intern.h | 32 ++-
drivers/crypto/caam/jr.c | 3 +-
drivers/crypto/caam/regs.h | 11 +-
drivers/crypto/caam/trng.c | 89 +++++++++
9 files changed, 320 insertions(+), 375 deletions(-)
delete mode 100644 drivers/crypto/caam/caamrng.c
create mode 100644 drivers/crypto/caam/drng.c
create mode 100644 drivers/crypto/caam/trng.c

--
2.21.0


2019-12-03 16:24:38

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v5 2/4] crypto: caam - move RNG presence check into a shared function

Move the code to check if RNG block is instantiated into a shared
function. This will be used by commits that follow.

Signed-off-by: Andrey Smirnov <[email protected]>
Tested-by: Chris Healy <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: Horia Geantă <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Iuliana Prodan <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
drivers/crypto/caam/caamrng.c | 10 +---------
drivers/crypto/caam/intern.h | 14 ++++++++++++++
2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c
index e8baacaabe07..041fbd015691 100644
--- a/drivers/crypto/caam/caamrng.c
+++ b/drivers/crypto/caam/caamrng.c
@@ -313,19 +313,11 @@ void caam_rng_exit(void)
int caam_rng_init(struct device *ctrldev)
{
struct device *dev;
- u32 rng_inst;
struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
int err;
init_done = false;

- /* Check for an instantiated RNG before registration */
- if (priv->era < 10)
- rng_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
- CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
- else
- rng_inst = rd_reg32(&priv->ctrl->vreg.rng) & CHA_VER_NUM_MASK;
-
- if (!rng_inst)
+ if (!caam_has_rng(priv))
return 0;

dev = caam_jr_alloc();
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index c7c10c90464b..f815e1ad4608 100644
--- a/drivers/crypto/caam/intern.h
+++ b/drivers/crypto/caam/intern.h
@@ -104,6 +104,20 @@ struct caam_drv_private {
#endif
};

+static inline bool caam_has_rng(struct caam_drv_private *priv)
+{
+ u32 rng_inst;
+
+ /* Check for an instantiated RNG before registration */
+ if (priv->era < 10)
+ rng_inst = (rd_reg32(&priv->ctrl->perfmon.cha_num_ls) &
+ CHA_ID_LS_RNG_MASK) >> CHA_ID_LS_RNG_SHIFT;
+ else
+ rng_inst = rd_reg32(&priv->ctrl->vreg.rng) & CHA_VER_NUM_MASK;
+
+ return rng_inst;
+}
+
#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API

int caam_algapi_init(struct device *dev);
--
2.21.0

2019-12-03 16:26:42

by Andrey Smirnov

[permalink] [raw]
Subject: [PATCH v5 4/4] crypto: caam - expose SEC4 DRNG via crypto RNG API

Expose SEC4 DRNG IP block using crypto RNG API so it could be used
both by kernel and userspace code.

Signed-off-by: Andrey Smirnov <[email protected]>
Tested-by: Chris Healy <[email protected]>
Cc: Chris Healy <[email protected]>
Cc: Lucas Stach <[email protected]>
Cc: Horia Geantă <[email protected]>
Cc: Herbert Xu <[email protected]>
Cc: Iuliana Prodan <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
---
drivers/crypto/caam/Kconfig | 8 ++
drivers/crypto/caam/Makefile | 1 +
drivers/crypto/caam/drng.c | 174 +++++++++++++++++++++++++++++++++++
drivers/crypto/caam/intern.h | 13 +++
drivers/crypto/caam/jr.c | 1 +
5 files changed, 197 insertions(+)
create mode 100644 drivers/crypto/caam/drng.c

diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig
index 31ecf165bc03..b6d9f3caa9ba 100644
--- a/drivers/crypto/caam/Kconfig
+++ b/drivers/crypto/caam/Kconfig
@@ -146,6 +146,14 @@ config CRYPTO_DEV_FSL_CAAM_PKC_API
Supported cryptographic primitives: encryption, decryption,
signature and verification.

+config CRYPTO_DEV_FSL_CAAM_DRNG_API
+ bool "Register caam device for hwrng API"
+ default y
+ select CRYPTO_RNG
+ help
+ Selecting this will register the SEC4 DRNG to
+ the crypto RNG API.
+
endif # CRYPTO_DEV_FSL_CAAM_JR

endif # CRYPTO_DEV_FSL_CAAM
diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile
index 04884fc087f9..02b7ed8823ce 100644
--- a/drivers/crypto/caam/Makefile
+++ b/drivers/crypto/caam/Makefile
@@ -20,6 +20,7 @@ caam_jr-y := jr.o key_gen.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += caamalg_qi.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o
+caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_DRNG_API) += drng.o
caam_jr-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caampkc.o pkc_desc.o

caam-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_QI) += qi.o
diff --git a/drivers/crypto/caam/drng.c b/drivers/crypto/caam/drng.c
new file mode 100644
index 000000000000..88b13a54e90f
--- /dev/null
+++ b/drivers/crypto/caam/drng.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver to expose SEC4 DRNG via crypto RNG API
+ *
+ * Copyright 2019 Zodiac Inflight Innovations
+ *
+ * Based on CAAM SEC4 hw_random driver
+ *
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2018-2019 NXP
+ *
+ * Based on caamalg.c crypto API driver.
+ *
+ */
+
+#include <linux/completion.h>
+#include <linux/atomic.h>
+
+#include <crypto/internal/rng.h>
+
+#include "compat.h"
+
+#include "regs.h"
+#include "intern.h"
+#include "desc_constr.h"
+#include "jr.h"
+#include "error.h"
+
+#define CAAM_DRNG_MAX_FIFO_STORE_SIZE ((unsigned int)U16_MAX)
+
+/* rng per-device context */
+struct caam_drng_ctx {
+ struct device *jrdev;
+ struct completion done;
+};
+
+static void rng_done(struct device *jrdev, u32 *desc, u32 err, void *context)
+{
+ struct caam_drng_ctx *ctx = context;
+
+ if (err)
+ caam_jr_strstatus(jrdev, err);
+
+ complete(&ctx->done);
+}
+
+static int caam_drng_generate(struct crypto_rng *tfm,
+ const u8 *src, unsigned int slen,
+ u8 *dst, unsigned int dlen)
+{
+ struct caam_drng_ctx *ctx = crypto_rng_ctx(tfm);
+ struct device *jrdev = ctx->jrdev;
+ unsigned int residue = dlen;
+ dma_addr_t dst_dma, cur_dma;
+ u32 *desc;
+ int ret;
+
+ desc = kzalloc(5 * CAAM_CMD_SZ + CAAM_PTR_SZ_MAX,
+ GFP_KERNEL | GFP_DMA);
+ if (!desc)
+ return -ENOMEM;
+
+ cur_dma = dst_dma = dma_map_single(jrdev, dst, dlen, DMA_FROM_DEVICE);
+ if (dma_mapping_error(jrdev, dst_dma)) {
+ dev_err(jrdev, "unable to map destination memory\n");
+ ret = -ENOMEM;
+ goto free_mem;
+ }
+
+ do {
+ const unsigned int chunk = min(residue,
+ CAAM_DRNG_MAX_FIFO_STORE_SIZE);
+
+ init_job_desc(desc, 0);
+ /* Generate random bytes */
+ append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG);
+ /* Store bytes */
+ append_seq_out_ptr_intlen(desc, cur_dma, chunk, 0);
+ append_seq_fifo_store(desc, chunk, FIFOST_TYPE_RNGSTORE);
+
+ print_hex_dump_debug("rng job desc@: ", DUMP_PREFIX_ADDRESS,
+ 16, 4, desc, desc_bytes(desc), 1);
+
+ init_completion(&ctx->done);
+ ret = caam_jr_enqueue(jrdev, desc, rng_done, ctx);
+ if (ret)
+ break;
+
+ wait_for_completion(&ctx->done);
+
+ cur_dma += chunk;
+ residue -= chunk;
+ } while (residue);
+
+ dma_unmap_single(jrdev, dst_dma, dlen, DMA_FROM_DEVICE);
+free_mem:
+ kfree(desc);
+ return ret;
+}
+
+static int caam_drng_init(struct crypto_tfm *tfm)
+{
+ struct caam_drng_ctx *ctx = crypto_tfm_ctx(tfm);
+ int ret;
+
+ ctx->jrdev = caam_jr_alloc();
+ ret = PTR_ERR_OR_ZERO(ctx->jrdev);
+ if (ret) {
+ pr_err("Job Ring Device allocation for transform failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void caam_drng_exit(struct crypto_tfm *tfm)
+{
+ struct caam_drng_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ caam_jr_free(ctx->jrdev);
+}
+
+static int caam_drng_seed(struct crypto_rng *tfm,
+ const u8 *seed, unsigned int slen)
+{
+ return 0;
+}
+
+static struct rng_alg caam_drng_alg = {
+ .generate = caam_drng_generate,
+ .seed = caam_drng_seed,
+ .seedsize = 0,
+ .base = {
+ .cra_name = "stdrng",
+ .cra_driver_name = "drng-caam",
+ .cra_priority = 300,
+ .cra_ctxsize = sizeof(struct caam_drng_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_init = caam_drng_init,
+ .cra_exit = caam_drng_exit,
+ },
+};
+
+static void caam_drng_unregister(void *data)
+{
+ crypto_unregister_rng(&caam_drng_alg);
+}
+
+int caam_drng_register(struct device *ctrldev)
+{
+ struct caam_drv_private *priv = dev_get_drvdata(ctrldev);
+
+ if (caam_has_rng(priv)) {
+ int ret;
+
+ ret = crypto_register_rng(&caam_drng_alg);
+ if (ret) {
+ dev_err(ctrldev,
+ "couldn't register rng crypto alg: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = devm_add_action_or_reset(ctrldev, caam_drng_unregister,
+ NULL);
+ if (ret)
+ return ret;
+
+ dev_info(ctrldev,
+ "registering %s\n", caam_drng_alg.base.cra_name);
+ }
+
+ return 0;
+}
diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h
index 54bb04aa86bd..0c81eefd13a9 100644
--- a/drivers/crypto/caam/intern.h
+++ b/drivers/crypto/caam/intern.h
@@ -185,6 +185,19 @@ static inline int caam_trng_register(struct device *dev)

#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API */

+#ifdef CONFIG_CRYPTO_DEV_FSL_CAAM_DRNG_API
+
+int caam_drng_register(struct device *dev);
+
+#else
+
+static inline int caam_drng_register(struct device *dev)
+{
+ return 0;
+}
+
+#endif /* CONFIG_CRYPTO_DEV_FSL_CAAM_DRNG_API */
+
#ifdef CONFIG_CAAM_QI

int caam_qi_algapi_init(struct device *dev);
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index c745b7044fe6..e68ba0606e3f 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -38,6 +38,7 @@ static void register_algs(struct device *dev)
caam_algapi_hash_init(dev);
caam_pkc_init(dev);
caam_qi_algapi_init(dev);
+ caam_drng_register(dev);

algs_unlock:
mutex_unlock(&algs_lock);
--
2.21.0

2019-12-09 15:45:16

by Horia Geanta

[permalink] [raw]
Subject: Re: [PATCH v5 0/4] enable CAAM's HWRNG as default

On 12/3/2019 6:24 PM, Andrey Smirnov wrote:
> Everyone:
>
> This series is a continuation of original [discussion]. I don't know
> if what's in the series is enough to use CAAMs HWRNG system wide, but
> I am hoping that with enough iterations and feedback it will be.
>
> Changes since [v1]:
>
> - Original hw_random replaced with the one using output of TRNG directly
>
> - SEC4 DRNG IP block exposed via crypto API
>
> - Small fix regarding use of GFP_DMA added to the series
>
> Chagnes since [v2]:
>
> - msleep in polling loop to avoid wasting CPU cycles
>
> - caam_trng_read() bails out early if 'wait' is set to 'false'
>
> - fixed typo in ZII's name
>
> Changes since [v3]:
>
> - DRNG's .cra_name is now "stdrng"
>
> - collected Reviewd-by tag from Lucas
>
> - typo fixes in commit messages of the series
>
> Changes since [v4]:
>
> - Dropped "crypto: caam - RNG4 TRNG errata" and "crypto: caam -
> enable prediction resistance in HRWNG" to limit the scope of the
> series. Those two patches are not yet ready and can be submitted
> separately later.
>
I don't agree with dropping the Job Ring Interface (JRI) in favor of
using TRNG registers directly - for the purpose of extracting entropy.

One of the reasons is that TRNG registers are part of page 0,
which is not accessible in the Linux kernel in some cases.

It's possible to use JRI for extracting entropy following these steps:

1. Instantiate RNG state handle with Prediction Resistance (PR) support
This is optional in cases when page 0 is not under kernel's control.
We'll separately modify SW controlling page 0 to offer PR support.

2. For each hwrng read(), enqueue via JRI one or more job descriptors (JD)
having the PR bit set in the ALGORITHM OPERATION command.

Note that according to hwrng API, it's ok to *partially* fulfill the request:
* @read: New API. drivers can fill up to max bytes of data
* into the buffer. The buffer is aligned for any type
* and max is a multiple of 4 and >= 32 bytes.

It's important to limit the output of each JD, such that the recommendation
in SP800-90C (section "9.4 The Oversampling-NRBG Construction") is followed:
https://csrc.nist.gov/CSRC/media/Publications/sp/800-90c/draft/documents/sp800_90c_second_draft.pdf

For CAAM RNG4, the DRBG security strength is s = 256 bits (32 bytes),
thus each JD must extract at most s/2 - 128 bits (16 bytes).

Similar to what's being done for TRNG registers-based implementation,
some back-off mechanism is needed, such that DECO won't stall
waiting for the TRNG.
This is important on i.MX platforms where there's a single DECO
(on PPC & Layerscape platforms there are multiple DECOs).

Horia