linux-crypto.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] General Key Derivation Function Support
       [not found]   ` <20190109082103.GA8586@sol.localdomain>
@ 2019-01-11 19:08     ` Stephan Müller
  2019-01-11 19:09       ` [PATCH 1/6] crypto: add template handling for RNGs Stephan Müller
                         ` (6 more replies)
  0 siblings, 7 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-11 19:08 UTC (permalink / raw)
  To: Eric Biggers, Herbert Xu
  Cc: James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Hi Herbert, Eric,

key derivation functions behave like a random number generator requiring
a seed and can generate arbitrarily-sized bit sequences. As KDFs wrap
ciphers, the first patch adds template support for the RNG part of the
kernel crypto API. This allows the KDFs to be implemented as templates.

The patches two through five add different KDFs. The immediate use in
the kernel are:

- SP800-108: security/keys/dh.c

- HKDF: As Eric Biggers outlined, he wants to use HKDF for Ext4 FBE

Other areas of the kernel implement KDFs which should be migrated to the
common code base offered with this patch.

The last patch adds the KDF invocation to tcrypt to allow an immediate
test invocation of the KDFs which is at least needed for FIPS 140-2
compliance where the tcrypt module is insmod'ed during boot time to
trigger the self tests.

Eric, considering your request for supporting parallel use of HKDF, I
instantiate the HMAC twice: once for the extract and once for the expand
phase. The idea is that an extract operation does not collide too much
with the expand operation (when using one instance of HMAC, the extract
phase would invoke setkey with the salt and thus affect the expand phase).
Though, the final extract phase setkey call with the PRK is non-atomic (at
least in the software HMAC implementation). Thus, the caller would need
to guarantee to invoke the extract phase while no expand phase operation
is performed. So, maintaining two HMAC instances is not really required
after all. What is your take on that?

Stephan Mueller (6):
  crypto: add template handling for RNGs
  crypto: kdf - SP800-108 Key Derivation Function
  crypto: kdf - add known answer tests
  crypto: hkdf - RFC5869 Key Derivation Function
  crypto: hkdf - add known answer tests
  crypto: tcrypt - add KDF test invocation

 crypto/Kconfig                |  13 +
 crypto/Makefile               |   2 +
 crypto/hkdf.c                 | 290 ++++++++++++++++++++
 crypto/kdf.c                  | 492 ++++++++++++++++++++++++++++++++++
 crypto/rng.c                  |  44 +++
 crypto/tcrypt.c               |   8 +
 crypto/testmgr.c              | 258 ++++++++++++++++++
 crypto/testmgr.h              | 225 ++++++++++++++++
 include/crypto/internal/rng.h |  26 ++
 9 files changed, 1358 insertions(+)
 create mode 100644 crypto/hkdf.c
 create mode 100644 crypto/kdf.c

-- 
2.20.1

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 1/6] crypto: add template handling for RNGs
  2019-01-11 19:08     ` [PATCH 0/6] General Key Derivation Function Support Stephan Müller
@ 2019-01-11 19:09       ` Stephan Müller
  2019-01-11 19:10       ` [PATCH 2/6] crypto: kdf - SP800-108 Key Derivation Function Stephan Müller
                         ` (5 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-11 19:09 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Add ability to register templates for RNGs. RNGs are
"meta" mechanisms using raw cipher primitives. Thus, RNGs can now be
implemented as templates to allow the complete flexibility the kernel
crypto API provides.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/rng.c                  | 44 +++++++++++++++++++++++++++++++++++
 include/crypto/internal/rng.h | 26 +++++++++++++++++++++
 2 files changed, 70 insertions(+)

diff --git a/crypto/rng.c b/crypto/rng.c
index 33c38a72bff5..da4fd03c0acd 100644
--- a/crypto/rng.c
+++ b/crypto/rng.c
@@ -64,6 +64,25 @@ static int crypto_rng_init_tfm(struct crypto_tfm *tfm)
 	return 0;
 }
 
+static inline struct rng_alg *__crypto_rng_alg(struct crypto_alg *alg)
+{
+	return container_of(alg, struct rng_alg, base);
+}
+
+static inline struct rng_instance *rng_instance(
+	struct crypto_instance *inst)
+{
+	return container_of(__crypto_rng_alg(&inst->alg),
+			    struct rng_instance, alg);
+}
+
+static void crypto_rng_free_instance(struct crypto_instance *inst)
+{
+	struct rng_instance *rng = rng_instance(inst);
+
+	rng->free(rng);
+}
+
 static unsigned int seedsize(struct crypto_alg *alg)
 {
 	struct rng_alg *ralg = container_of(alg, struct rng_alg, base);
@@ -102,6 +121,7 @@ static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
 static const struct crypto_type crypto_rng_type = {
 	.extsize = crypto_alg_extsize,
 	.init_tfm = crypto_rng_init_tfm,
+	.free = crypto_rng_free_instance,
 #ifdef CONFIG_PROC_FS
 	.show = crypto_rng_show,
 #endif
@@ -229,5 +249,29 @@ void crypto_unregister_rngs(struct rng_alg *algs, int count)
 }
 EXPORT_SYMBOL_GPL(crypto_unregister_rngs);
 
+static int rng_prepare_alg(struct rng_alg *alg)
+{
+	struct crypto_alg *base = &alg->base;
+
+	base->cra_type = &crypto_rng_type;
+	base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+	base->cra_flags |= CRYPTO_ALG_TYPE_RNG;
+
+	return 0;
+}
+
+int rng_register_instance(struct crypto_template *tmpl,
+			  struct rng_instance *inst)
+{
+	int err;
+
+	err = rng_prepare_alg(&inst->alg);
+	if (err)
+		return err;
+
+	return crypto_register_instance(tmpl, rng_crypto_instance(inst));
+}
+EXPORT_SYMBOL_GPL(rng_register_instance);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Random Number Generator");
diff --git a/include/crypto/internal/rng.h b/include/crypto/internal/rng.h
index a52ef3483dd7..bfe4482ad336 100644
--- a/include/crypto/internal/rng.h
+++ b/include/crypto/internal/rng.h
@@ -42,4 +42,30 @@ static inline void crypto_rng_set_entropy(struct crypto_rng *tfm,
 	crypto_rng_alg(tfm)->set_ent(tfm, data, len);
 }
 
+struct rng_instance {
+	void (*free)(struct rng_instance *inst);
+	struct rng_alg alg;
+};
+
+static inline struct rng_instance *rng_alloc_instance(
+	const char *name, struct crypto_alg *alg)
+{
+	return crypto_alloc_instance(name, alg,
+			      sizeof(struct rng_instance) - sizeof(*alg));
+}
+
+static inline struct crypto_instance *rng_crypto_instance(
+	struct rng_instance *inst)
+{
+	return container_of(&inst->alg.base, struct crypto_instance, alg);
+}
+
+static inline void *rng_instance_ctx(struct rng_instance *inst)
+{
+	return crypto_instance_ctx(rng_crypto_instance(inst));
+}
+
+int rng_register_instance(struct crypto_template *tmpl,
+			  struct rng_instance *inst);
+
 #endif
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 2/6] crypto: kdf - SP800-108 Key Derivation Function
  2019-01-11 19:08     ` [PATCH 0/6] General Key Derivation Function Support Stephan Müller
  2019-01-11 19:09       ` [PATCH 1/6] crypto: add template handling for RNGs Stephan Müller
@ 2019-01-11 19:10       ` Stephan Müller
  2019-01-12  5:27         ` Eric Biggers
  2019-01-11 19:10       ` [PATCH 3/6] crypto: kdf - add known answer tests Stephan Müller
                         ` (4 subsequent siblings)
  6 siblings, 1 reply; 36+ messages in thread
From: Stephan Müller @ 2019-01-11 19:10 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

The SP800-108 compliant Key Derivation Function is implemented as a
random number generator considering that it behaves like a deterministic
RNG.

All three KDF types specified in SP800-108 are implemented.

The code comments provide details about how to invoke the different KDF
types.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/Kconfig  |   7 +
 crypto/Makefile |   1 +
 crypto/kdf.c    | 492 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 500 insertions(+)
 create mode 100644 crypto/kdf.c

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 86960aa53e0f..cc80d89e0cf5 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -561,6 +561,13 @@ config CRYPTO_HMAC
 	  HMAC: Keyed-Hashing for Message Authentication (RFC2104).
 	  This is required for IPSec.
 
+config CRYPTO_KDF
+	tristate "Key Derivation Function (SP800-108)"
+	select CRYPTO_RNG
+	help
+	  Support for KDF compliant to SP800-108. All three types of
+	  KDF specified in SP800-108 are implemented.
+
 config CRYPTO_XCBC
 	tristate "XCBC support"
 	select CRYPTO_HASH
diff --git a/crypto/Makefile b/crypto/Makefile
index 799ed5e94606..69a0bb64b0ac 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -58,6 +58,7 @@ crypto_user-y := crypto_user_base.o
 crypto_user-$(CONFIG_CRYPTO_STATS) += crypto_user_stat.o
 obj-$(CONFIG_CRYPTO_CMAC) += cmac.o
 obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
+obj-$(CONFIG_CRYPTO_KDF) += kdf.o
 obj-$(CONFIG_CRYPTO_VMAC) += vmac.o
 obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
 obj-$(CONFIG_CRYPTO_NULL2) += crypto_null.o
diff --git a/crypto/kdf.c b/crypto/kdf.c
new file mode 100644
index 000000000000..2c6dd8676a9f
--- /dev/null
+++ b/crypto/kdf.c
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * SP800-108 Key-derivation function
+ *
+ * Copyright (C) 2019, Stephan Mueller <smueller@chronox.de>
+ */
+
+/*
+ * For performing a KDF operation, the following input is required
+ * from the caller:
+ *
+ *	* Keying material to be used to derive the new keys from
+ *	  (denoted as Ko in SP800-108)
+ *	* Label -- a free form binary string
+ *	* Context -- a free form binary string
+ *
+ * The KDF is implemented as a random number generator.
+ *
+ * The Ko keying material is to be provided with the initialization of the KDF
+ * "random number generator", i.e. with the crypto_rng_reset function.
+ *
+ * The Label and Context concatenated string is provided when obtaining random
+ * numbers, i.e. with the crypto_rng_generate function. The caller must format
+ * the free-form Label || Context input as deemed necessary for the given
+ * purpose. Note, SP800-108 mandates that the Label and Context are separated
+ * by a 0x00 byte, i.e. the caller shall provide the input as
+ * Label || 0x00 || Context when trying to be compliant to SP800-108. For
+ * the feedback KDF, an IV is required as documented below.
+ *
+ * Example without proper error handling:
+ *	char *keying_material = "\x00\x11\x22\x33\x44\x55\x66\x77";
+ *	char *label_context = "\xde\xad\xbe\xef\x00\xde\xad\xbe\xef";
+ *	kdf = crypto_alloc_rng(name, 0, 0);
+ *	crypto_rng_reset(kdf, keying_material, 8);
+ *	crypto_rng_generate(kdf, label_context, 9, outbuf, outbuflen);
+ *
+ * NOTE: In-place cipher operations are not supported.
+ */
+
+#include <linux/module.h>
+#include <crypto/rng.h>
+#include <crypto/internal/rng.h>
+#include <crypto/hash.h>
+#include <crypto/internal/hash.h>
+
+struct crypto_kdf_ctx {
+	struct crypto_shash *kmd;
+};
+
+#define CRYPTO_KDF_MAX_DIGESTSIZE	64
+#define CRYPTO_KDF_MAX_ALIGNMASK	0x3f
+
+static inline void crypto_kdf_init_desc(struct shash_desc *desc,
+					struct crypto_shash *kmd)
+{
+	desc->tfm = kmd;
+	desc->flags = crypto_shash_get_flags(kmd) & CRYPTO_TFM_REQ_MAY_SLEEP;
+}
+
+/*
+ * Implementation of the KDF in double pipeline iteration mode according with
+ * counter to SP800-108 section 5.3.
+ *
+ * The caller must provide Label || 0x00 || Context in src. This src pointer
+ * may also be NULL if the caller wishes not to provide anything.
+ */
+static int crypto_kdf_dpi_random(struct crypto_rng *rng,
+				 const u8 *src, unsigned int slen,
+				 u8 *dst, unsigned int dlen)
+{
+	struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	struct crypto_shash *kmd = ctx->kmd;
+	SHASH_DESC_ON_STACK(desc, kmd);
+	__be32 counter = cpu_to_be32(1);
+	unsigned int h = crypto_shash_digestsize(kmd);
+	unsigned int alignmask = crypto_shash_alignmask(kmd);
+	int err = 0;
+	u8 *dst_orig = dst;
+	u8 Aiblock[CRYPTO_KDF_MAX_DIGESTSIZE + CRYPTO_KDF_MAX_ALIGNMASK];
+	u8 *Ai = PTR_ALIGN((u8 *)Aiblock, alignmask + 1);
+
+	crypto_kdf_init_desc(desc, kmd);
+
+	memset(Ai, 0, h);
+
+	while (dlen) {
+		/* Calculate A(i) */
+		if (dst == dst_orig && src && slen)
+			/* 5.3 step 4 and 5.a */
+			err = crypto_shash_digest(desc, src, slen, Ai);
+		else
+			/* 5.3 step 5.a */
+			err = crypto_shash_digest(desc, Ai, h, Ai);
+		if (err)
+			goto out;
+
+		/* Calculate K(i) -- step 5.b */
+		err = crypto_shash_init(desc);
+		if (err)
+			goto out;
+
+		err = crypto_shash_update(desc, Ai, h);
+		if (err)
+			goto out;
+
+		err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32));
+		if (err)
+			goto out;
+		if (src && slen) {
+			err = crypto_shash_update(desc, src, slen);
+			if (err)
+				goto out;
+		}
+
+		if (dlen < h) {
+			u8 tmpbuffer[CRYPTO_KDF_MAX_DIGESTSIZE];
+
+			err = crypto_shash_final(desc, tmpbuffer);
+			if (err)
+				goto out;
+			memcpy(dst, tmpbuffer, dlen);
+			memzero_explicit(tmpbuffer, h);
+			goto out;
+		} else {
+			err = crypto_shash_final(desc, dst);
+			if (err)
+				goto out;
+			dlen -= h;
+			dst += h;
+			counter = cpu_to_be32(be32_to_cpu(counter) + 1);
+		}
+	}
+
+out:
+	if (err)
+		memzero_explicit(dst_orig, dlen);
+	shash_desc_zero(desc);
+	memzero_explicit(Ai, h);
+	return err;
+}
+
+/*
+ * Implementation of the KDF in feedback mode with a non-NULL IV and with
+ * counter according to SP800-108 section 5.2. The IV is supplied with src
+ * and must be equal to the digestsize of the used cipher.
+ *
+ * In addition, the caller must provide Label || 0x00 || Context in src. This
+ * src pointer must not be NULL as the IV is required. The ultimate format of
+ * the src pointer is IV || Label || 0x00 || Context where the length of the
+ * IV is equal to the output size of the PRF.
+ */
+static int crypto_kdf_fb_random(struct crypto_rng *rng,
+				const u8 *src, unsigned int slen,
+				u8 *dst, unsigned int dlen)
+{
+	struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	struct crypto_shash *kmd = ctx->kmd;
+	SHASH_DESC_ON_STACK(desc, kmd);
+	__be32 counter = cpu_to_be32(1);
+	unsigned int h = crypto_shash_digestsize(kmd), labellen = 0;
+	int err = 0;
+	u8 *dst_orig = dst;
+	const u8 *label;
+
+	/* require the presence of an IV */
+	if (!src || slen < h)
+		return -EINVAL;
+
+	crypto_kdf_init_desc(desc, kmd);
+
+	/* calculate the offset of the label / context data */
+	label = src + h;
+	labellen = slen - h;
+
+	while (dlen) {
+		err = crypto_shash_init(desc);
+		if (err)
+			goto out;
+
+		/*
+		 * Feedback mode applies to all rounds except first which uses
+		 * the IV.
+		 */
+		if (dst_orig == dst)
+			err = crypto_shash_update(desc, src, h);
+		else
+			err = crypto_shash_update(desc, dst - h, h);
+		if (err)
+			goto out;
+
+		err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32));
+		if (err)
+			goto out;
+		if (labellen) {
+			err = crypto_shash_update(desc, label, labellen);
+			if (err)
+				goto out;
+		}
+
+		if (dlen < h) {
+			u8 tmpbuffer[CRYPTO_KDF_MAX_DIGESTSIZE];
+
+			err = crypto_shash_final(desc, tmpbuffer);
+			if (err)
+				goto out;
+			memcpy(dst, tmpbuffer, dlen);
+			memzero_explicit(tmpbuffer, h);
+			goto out;
+		} else {
+			err = crypto_shash_final(desc, dst);
+			if (err)
+				goto out;
+			dlen -= h;
+			dst += h;
+			counter = cpu_to_be32(be32_to_cpu(counter) + 1);
+		}
+	}
+
+out:
+	if (err)
+		memzero_explicit(dst_orig, dlen);
+	return err;
+}
+
+/*
+ * Implementation of the KDF in counter mode according to SP800-108 section 5.1
+ * as well as SP800-56A section 5.8.1 (Single-step KDF).
+ *
+ * SP800-108:
+ * The caller must provide Label || 0x00 || Context in src. This src pointer
+ * may also be NULL if the caller wishes not to provide anything.
+ *
+ * SP800-56A:
+ * The key provided for the HMAC during the crypto_rng_reset shall NOT be the
+ * shared secret from the DH operation, but an independently generated key.
+ * The src pointer is defined as Z || other info where Z is the shared secret
+ * from DH and other info is an arbitrary string (see SP800-56A section
+ * 5.8.1.2).
+ */
+static int crypto_kdf_ctr_random(struct crypto_rng *rng,
+				 const u8 *src, unsigned int slen,
+				 u8 *dst, unsigned int dlen)
+{
+	struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	struct crypto_shash *kmd = ctx->kmd;
+	SHASH_DESC_ON_STACK(desc, kmd);
+	__be32 counter = cpu_to_be32(1);
+	unsigned int h = crypto_shash_digestsize(kmd);
+	int err = 0;
+	u8 *dst_orig = dst;
+
+	crypto_kdf_init_desc(desc, kmd);
+
+	while (dlen) {
+		err = crypto_shash_init(desc);
+		if (err)
+			goto out;
+
+		err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32));
+		if (err)
+			goto out;
+
+		if (src && slen) {
+			err = crypto_shash_update(desc, src, slen);
+			if (err)
+				goto out;
+		}
+
+		if (dlen < h) {
+			u8 tmpbuffer[CRYPTO_KDF_MAX_DIGESTSIZE];
+
+			err = crypto_shash_final(desc, tmpbuffer);
+			if (err)
+				goto out;
+			memcpy(dst, tmpbuffer, dlen);
+			memzero_explicit(tmpbuffer, h);
+			return 0;
+		} else {
+			err = crypto_shash_final(desc, dst);
+			if (err)
+				goto out;
+
+			dlen -= h;
+			dst += h;
+			counter = cpu_to_be32(be32_to_cpu(counter) + 1);
+		}
+	}
+
+out:
+	if (err)
+		memzero_explicit(dst_orig, dlen);
+	shash_desc_zero(desc);
+	return err;
+}
+
+/*
+ * The seeding of the KDF allows to set a key which must be at least
+ * digestsize long.
+ */
+static int crypto_kdf_seed(struct crypto_rng *rng,
+			   const u8 *seed, unsigned int slen)
+{
+	struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	unsigned int ds = crypto_shash_digestsize(ctx->kmd);
+
+	/* Check according to SP800-108 section 7.2 */
+	if (ds > slen)
+		return -EINVAL;
+
+	/*
+	 * We require that we operate on a MAC -- if we do not operate on a
+	 * MAC, this function returns an error.
+	 */
+	return crypto_shash_setkey(ctx->kmd, seed, slen);
+}
+
+static int crypto_kdf_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+	struct crypto_shash_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_shash *kmd;
+	unsigned int ds;
+
+	kmd = crypto_spawn_shash(spawn);
+	if (IS_ERR(kmd))
+		return PTR_ERR(kmd);
+
+	ds = crypto_shash_digestsize(kmd);
+	/* Hashes with no digest size are not allowed for KDFs. */
+	if (!ds || ds > CRYPTO_KDF_MAX_DIGESTSIZE ||
+	    CRYPTO_KDF_MAX_ALIGNMASK < crypto_shash_alignmask(kmd)) {
+		crypto_free_shash(kmd);
+		return -EOPNOTSUPP;
+	}
+
+	ctx->kmd = kmd;
+
+	return 0;
+}
+
+static void crypto_kdf_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_shash(ctx->kmd);
+}
+
+static void crypto_kdf_free(struct rng_instance *inst)
+{
+	crypto_drop_spawn(rng_instance_ctx(inst));
+	kfree(inst);
+}
+
+static int crypto_kdf_alloc_common(struct crypto_template *tmpl,
+				   struct rtattr **tb,
+				   const u8 *name,
+				   int (*generate)(struct crypto_rng *tfm,
+						   const u8 *src,
+						   unsigned int slen,
+						   u8 *dst, unsigned int dlen))
+{
+	struct rng_instance *inst;
+	struct crypto_alg *alg;
+	struct shash_alg *salg;
+	int err;
+	unsigned int ds, ss;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_RNG);
+	if (err)
+		return err;
+
+	salg = shash_attr_alg(tb[1], 0, 0);
+	if (IS_ERR(salg))
+		return PTR_ERR(salg);
+
+	ds = salg->digestsize;
+	ss = salg->statesize;
+	alg = &salg->base;
+
+	inst = rng_alloc_instance(name, alg);
+	err = PTR_ERR(inst);
+	if (IS_ERR(inst))
+		goto out_put_alg;
+
+	err = crypto_init_shash_spawn(rng_instance_ctx(inst), salg,
+				      rng_crypto_instance(inst));
+	if (err)
+		goto out_free_inst;
+
+	inst->alg.base.cra_priority	= alg->cra_priority;
+	inst->alg.base.cra_blocksize	= alg->cra_blocksize;
+	inst->alg.base.cra_alignmask	= alg->cra_alignmask;
+
+	inst->alg.generate		= generate;
+	inst->alg.seed			= crypto_kdf_seed;
+	inst->alg.seedsize		= ds;
+
+	inst->alg.base.cra_init		= crypto_kdf_init_tfm;
+	inst->alg.base.cra_exit		= crypto_kdf_exit_tfm;
+	inst->alg.base.cra_ctxsize	= ALIGN(sizeof(struct crypto_kdf_ctx) +
+					  ss * 2, crypto_tfm_ctx_alignment());
+
+	inst->free			= crypto_kdf_free;
+
+	err = rng_register_instance(tmpl, inst);
+
+	if (err) {
+out_free_inst:
+		crypto_kdf_free(inst);
+	}
+
+out_put_alg:
+	crypto_mod_put(alg);
+	return err;
+}
+
+static int crypto_kdf_ctr_create(struct crypto_template *tmpl,
+				 struct rtattr **tb)
+{
+	return crypto_kdf_alloc_common(tmpl, tb, "kdf_ctr",
+				       crypto_kdf_ctr_random);
+}
+
+static struct crypto_template crypto_kdf_ctr_tmpl = {
+	.name = "kdf_ctr",
+	.create = crypto_kdf_ctr_create,
+	.module = THIS_MODULE,
+};
+
+static int crypto_kdf_fb_create(struct crypto_template *tmpl,
+				struct rtattr **tb) {
+	return crypto_kdf_alloc_common(tmpl, tb, "kdf_fb",
+				       crypto_kdf_fb_random);
+}
+
+static struct crypto_template crypto_kdf_fb_tmpl = {
+	.name = "kdf_fb",
+	.create = crypto_kdf_fb_create,
+	.module = THIS_MODULE,
+};
+
+static int crypto_kdf_dpi_create(struct crypto_template *tmpl,
+				 struct rtattr **tb) {
+	return crypto_kdf_alloc_common(tmpl, tb, "kdf_dpi",
+				       crypto_kdf_dpi_random);
+}
+
+static struct crypto_template crypto_kdf_dpi_tmpl = {
+	.name = "kdf_dpi",
+	.create = crypto_kdf_dpi_create,
+	.module = THIS_MODULE,
+};
+
+static int __init crypto_kdf_init(void)
+{
+	int err = crypto_register_template(&crypto_kdf_ctr_tmpl);
+
+	if (err)
+		return err;
+
+	err = crypto_register_template(&crypto_kdf_fb_tmpl);
+	if (err) {
+		crypto_unregister_template(&crypto_kdf_ctr_tmpl);
+		return err;
+	}
+
+	err = crypto_register_template(&crypto_kdf_dpi_tmpl);
+	if (err) {
+		crypto_unregister_template(&crypto_kdf_ctr_tmpl);
+		crypto_unregister_template(&crypto_kdf_fb_tmpl);
+	}
+	return err;
+}
+
+static void __exit crypto_kdf_exit(void)
+{
+	crypto_unregister_template(&crypto_kdf_ctr_tmpl);
+	crypto_unregister_template(&crypto_kdf_fb_tmpl);
+	crypto_unregister_template(&crypto_kdf_dpi_tmpl);
+}
+
+module_init(crypto_kdf_init);
+module_exit(crypto_kdf_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("Key Derivation Function according to SP800-108");
+MODULE_ALIAS_CRYPTO("kdf_ctr");
+MODULE_ALIAS_CRYPTO("kdf_fb");
+MODULE_ALIAS_CRYPTO("kdf_dpi");
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 3/6] crypto: kdf - add known answer tests
  2019-01-11 19:08     ` [PATCH 0/6] General Key Derivation Function Support Stephan Müller
  2019-01-11 19:09       ` [PATCH 1/6] crypto: add template handling for RNGs Stephan Müller
  2019-01-11 19:10       ` [PATCH 2/6] crypto: kdf - SP800-108 Key Derivation Function Stephan Müller
@ 2019-01-11 19:10       ` Stephan Müller
  2019-01-12  5:26         ` Eric Biggers
  2019-01-11 19:10       ` [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function Stephan Müller
                         ` (3 subsequent siblings)
  6 siblings, 1 reply; 36+ messages in thread
From: Stephan Müller @ 2019-01-11 19:10 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Add known answer tests to the testmgr for the KDF (SP800-108) cipher.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/testmgr.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++
 crypto/testmgr.h | 110 +++++++++++++++++++++++
 2 files changed, 336 insertions(+)

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 0f684a414acb..ff9051bffa1f 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -110,6 +110,11 @@ struct drbg_test_suite {
 	unsigned int count;
 };
 
+struct kdf_test_suite {
+	struct kdf_testvec *vecs;
+	unsigned int count;
+};
+
 struct akcipher_test_suite {
 	const struct akcipher_testvec *vecs;
 	unsigned int count;
@@ -133,6 +138,7 @@ struct alg_test_desc {
 		struct hash_test_suite hash;
 		struct cprng_test_suite cprng;
 		struct drbg_test_suite drbg;
+		struct kdf_test_suite kdf;
 		struct akcipher_test_suite akcipher;
 		struct kpp_test_suite kpp;
 	} suite;
@@ -2020,6 +2026,64 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr,
 	return ret;
 }
 
+static int kdf_cavs_test(struct kdf_testvec *test,
+			 const char *driver, u32 type, u32 mask)
+{
+	int ret = -EAGAIN;
+	struct crypto_rng *drng;
+	unsigned char *buf = kzalloc(test->expectedlen, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	drng = crypto_alloc_rng(driver, type | CRYPTO_ALG_INTERNAL, mask);
+	if (IS_ERR(drng)) {
+		printk(KERN_ERR "alg: kdf: could not allocate cipher handle "
+		       "for %s\n", driver);
+		kzfree(buf);
+		return -ENOMEM;
+	}
+
+	ret = crypto_rng_reset(drng, test->K1, test->K1len);
+	if (ret) {
+		printk(KERN_ERR "alg: kdf: could not set key derivation key\n");
+		goto err;
+	}
+
+	ret = crypto_rng_generate(drng, test->context, test->contextlen,
+				  buf, test->expectedlen);
+	if (ret) {
+		printk(KERN_ERR "alg: kdf: could not obtain key data\n");
+		goto err;
+	}
+
+	ret = memcmp(test->expected, buf, test->expectedlen);
+
+err:
+	crypto_free_rng(drng);
+	kzfree(buf);
+	return ret;
+}
+
+static int alg_test_kdf(const struct alg_test_desc *desc, const char *driver,
+			u32 type, u32 mask)
+{
+	int err = 0;
+	unsigned int i = 0;
+	struct kdf_testvec *template = desc->suite.kdf.vecs;
+	unsigned int tcount = desc->suite.kdf.count;
+
+	for (i = 0; i < tcount; i++) {
+		err = kdf_cavs_test(&template[i], driver, type, mask);
+		if (err) {
+			printk(KERN_ERR "alg: kdf: Test %d failed for %s\n",
+			       i, driver);
+			err = -EINVAL;
+			break;
+		}
+	}
+	return err;
+}
 
 static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver,
 			 u32 type, u32 mask)
@@ -3220,6 +3284,168 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.alg = "jitterentropy_rng",
 		.fips_allowed = 1,
 		.test = alg_test_null,
+	}, {
+		.alg = "kdf_ctr(cmac(aes))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(cmac(des3_ede))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(hmac(sha1))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(hmac(sha224))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(hmac(sha256))",
+		.test = alg_test_kdf,
+		.fips_allowed = 1,
+		.suite = {
+			.kdf = {
+				.vecs = kdf_ctr_hmac_sha256_tv_template,
+				.count = ARRAY_SIZE(kdf_ctr_hmac_sha256_tv_template)
+			}
+		}
+	}, {
+		.alg = "kdf_ctr(hmac(sha384))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(hmac(sha512))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(sha1)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(sha224)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(sha256)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(sha384)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(sha512)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(cmac(aes))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(cmac(des3_ede))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(hmac(sha1))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(hmac(sha224))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(hmac(sha256))",
+		.test = alg_test_kdf,
+		.fips_allowed = 1,
+		.suite = {
+			.kdf = {
+				.vecs = kdf_dpi_hmac_sha256_tv_template,
+				.count = ARRAY_SIZE(kdf_dpi_hmac_sha256_tv_template)
+			}
+		}
+	}, {
+		.alg = "kdf_dpi(hmac(sha384))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(hmac(sha512))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(sha1)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(sha224)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(sha256)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(sha384)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(sha512)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(cmac(aes))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(cmac(des3_ede))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(hmac(sha1))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(hmac(sha224))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(hmac(sha256))",
+		.test = alg_test_kdf,
+		.fips_allowed = 1,
+		.suite = {
+			.kdf = {
+				.vecs = kdf_fb_hmac_sha256_tv_template,
+				.count = ARRAY_SIZE(kdf_fb_hmac_sha256_tv_template)
+			}
+		}
+	}, {
+		.alg = "kdf_fb(hmac(sha384))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(hmac(sha512))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(sha1)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(sha224)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(sha256)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(sha384)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(sha512)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
 	}, {
 		.alg = "kw(aes)",
 		.test = alg_test_skcipher,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index ca8e8ebef309..a729b66f8757 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -122,6 +122,15 @@ struct drbg_testvec {
 	size_t expectedlen;
 };
 
+struct kdf_testvec {
+	unsigned char *K1;
+	size_t K1len;
+	unsigned char *context;
+	size_t contextlen;
+	unsigned char *expected;
+	size_t expectedlen;
+};
+
 struct akcipher_testvec {
 	const unsigned char *key;
 	const unsigned char *m;
@@ -27892,6 +27901,107 @@ static const struct drbg_testvec drbg_nopr_ctr_aes128_tv_template[] = {
 	},
 };
 
+/*
+ * Test vector obtained from
+ * http://csrc.nist.gov/groups/STM/cavp/documents/KBKDF800-108/CounterMode.zip
+ */
+static struct kdf_testvec kdf_ctr_hmac_sha256_tv_template[] = {
+	{
+		.K1 = (unsigned char *)
+			"\xdd\x1d\x91\xb7\xd9\x0b\x2b\xd3"
+			"\x13\x85\x33\xce\x92\xb2\x72\xfb"
+			"\xf8\xa3\x69\x31\x6a\xef\xe2\x42"
+			"\xe6\x59\xcc\x0a\xe2\x38\xaf\xe0",
+		.K1len = 32,
+		.context = (unsigned char *)
+			"\x01\x32\x2b\x96\xb3\x0a\xcd\x19"
+			"\x79\x79\x44\x4e\x46\x8e\x1c\x5c"
+			"\x68\x59\xbf\x1b\x1c\xf9\x51\xb7"
+			"\xe7\x25\x30\x3e\x23\x7e\x46\xb8"
+			"\x64\xa1\x45\xfa\xb2\x5e\x51\x7b"
+			"\x08\xf8\x68\x3d\x03\x15\xbb\x29"
+			"\x11\xd8\x0a\x0e\x8a\xba\x17\xf3"
+			"\xb4\x13\xfa\xac",
+		.contextlen = 60,
+		.expected = (unsigned char *)
+			"\x10\x62\x13\x42\xbf\xb0\xfd\x40"
+			"\x04\x6c\x0e\x29\xf2\xcf\xdb\xf0",
+		.expectedlen = 16
+	}
+};
+
+/*
+ * Test vector obtained from
+ * http://csrc.nist.gov/groups/STM/cavp/documents/KBKDF800-108/FeedbackModeNOzeroiv.zip
+ */
+static struct kdf_testvec kdf_fb_hmac_sha256_tv_template[] = {
+	{
+		.K1 = (unsigned char *)
+			"\x93\xf6\x98\xe8\x42\xee\xd7\x53"
+			"\x94\xd6\x29\xd9\x57\xe2\xe8\x9c"
+			"\x6e\x74\x1f\x81\x0b\x62\x3c\x8b"
+			"\x90\x1e\x38\x37\x6d\x06\x8e\x7b",
+		.K1len = 32,
+		.context = (unsigned char *)
+			"\x9f\x57\x5d\x90\x59\xd3\xe0\xc0"
+			"\x80\x3f\x08\x11\x2f\x8a\x80\x6d"
+			"\xe3\xc3\x47\x19\x12\xcd\xf4\x2b"
+			"\x09\x53\x88\xb1\x4b\x33\x50\x8e"
+			"\x53\xb8\x9c\x18\x69\x0e\x20\x57"
+			"\xa1\xd1\x67\x82\x2e\x63\x6d\xe5"
+			"\x0b\xe0\x01\x85\x32\xc4\x31\xf7"
+			"\xf5\xe3\x7f\x77\x13\x92\x20\xd5"
+			"\xe0\x42\x59\x9e\xbe\x26\x6a\xf5"
+			"\x76\x7e\xe1\x8c\xd2\xc5\xc1\x9a"
+			"\x1f\x0f\x80",
+		.contextlen = 83,
+		.expected = (unsigned char *)
+			"\xbd\x14\x76\xf4\x3a\x4e\x31\x57"
+			"\x47\xcf\x59\x18\xe0\xea\x5b\xc0"
+			"\xd9\x87\x69\x45\x74\x77\xc3\xab"
+			"\x18\xb7\x42\xde\xf0\xe0\x79\xa9"
+			"\x33\xb7\x56\x36\x5a\xfb\x55\x41"
+			"\xf2\x53\xfe\xe4\x3c\x6f\xd7\x88"
+			"\xa4\x40\x41\x03\x85\x09\xe9\xee"
+			"\xb6\x8f\x7d\x65\xff\xbb\x5f\x95",
+		.expectedlen = 64
+	}
+};
+
+/*
+ * Test vector obtained from
+ * http://csrc.nist.gov/groups/STM/cavp/documents/KBKDF800-108/PipelineModewithCounter.zip
+ */
+static struct kdf_testvec kdf_dpi_hmac_sha256_tv_template[] = {
+	{
+		.K1 = (unsigned char *)
+			"\x02\xd3\x6f\xa0\x21\xc2\x0d\xdb"
+			"\xde\xe4\x69\xf0\x57\x94\x68\xba"
+			"\xe5\xcb\x13\xb5\x48\xb6\xc6\x1c"
+			"\xdf\x9d\x3e\xc4\x19\x11\x1d\xe2",
+		.K1len = 32,
+		.context = (unsigned char *)
+			"\x85\xab\xe3\x8b\xf2\x65\xfb\xdc"
+			"\x64\x45\xae\x5c\x71\x15\x9f\x15"
+			"\x48\xc7\x3b\x7d\x52\x6a\x62\x31"
+			"\x04\x90\x4a\x0f\x87\x92\x07\x0b"
+			"\x3d\xf9\x90\x2b\x96\x69\x49\x04"
+			"\x25\xa3\x85\xea\xdb\x0f\x9c\x76"
+			"\xe4\x6f\x0f",
+		.contextlen = 51,
+		.expected = (unsigned char *)
+			"\xd6\x9f\x74\xf5\x18\xc9\xf6\x4f"
+			"\x90\xa0\xbe\xeb\xab\x69\xf6\x89"
+			"\xb7\x3b\x5c\x13\xeb\x0f\x86\x0a"
+			"\x95\xca\xd7\xd9\x81\x4f\x8c\x50"
+			"\x6e\xb7\xb1\x79\xa5\xc5\xb4\x46"
+			"\x6a\x9e\xc1\x54\xc3\xbf\x1c\x13"
+			"\xef\xd6\xec\x0d\x82\xb0\x2c\x29"
+			"\xaf\x2c\x69\x02\x99\xed\xc4\x53",
+		.expectedlen = 64
+	}
+};
+
 /* Cast5 test vectors from RFC 2144 */
 static const struct cipher_testvec cast5_tv_template[] = {
 	{
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function
  2019-01-11 19:08     ` [PATCH 0/6] General Key Derivation Function Support Stephan Müller
                         ` (2 preceding siblings ...)
  2019-01-11 19:10       ` [PATCH 3/6] crypto: kdf - add known answer tests Stephan Müller
@ 2019-01-11 19:10       ` Stephan Müller
  2019-01-12  5:12         ` Eric Biggers
  2019-01-11 19:10       ` [PATCH 5/6] crypto: hkdf - add known answer tests Stephan Müller
                         ` (2 subsequent siblings)
  6 siblings, 1 reply; 36+ messages in thread
From: Stephan Müller @ 2019-01-11 19:10 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

The RFC5869 compliant Key Derivation Function is implemented as a
random number generator considering that it behaves like a deterministic
RNG.

The extract and expand phases use different instances of the underlying
keyed message digest cipher to ensure that while the extraction phase
generates a new key for the expansion phase, the cipher for the
expansion phase can still be used. This approach is intended to aid
multi-threaded uses cases.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/Kconfig  |   6 +
 crypto/Makefile |   1 +
 crypto/hkdf.c   | 290 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 297 insertions(+)
 create mode 100644 crypto/hkdf.c

diff --git a/crypto/Kconfig b/crypto/Kconfig
index cc80d89e0cf5..0eee5e129fa3 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -568,6 +568,12 @@ config CRYPTO_KDF
 	  Support for KDF compliant to SP800-108. All three types of
 	  KDF specified in SP800-108 are implemented.
 
+config CRYPTO_HKDF
+	tristate "HMAC-based Extract-and expand Key Derivation Function"
+	select CRYPTO_RNG
+	help
+	  Support for KDF compliant to RFC5869.
+
 config CRYPTO_XCBC
 	tristate "XCBC support"
 	select CRYPTO_HASH
diff --git a/crypto/Makefile b/crypto/Makefile
index 69a0bb64b0ac..6bbb0a4dea13 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -59,6 +59,7 @@ crypto_user-$(CONFIG_CRYPTO_STATS) += crypto_user_stat.o
 obj-$(CONFIG_CRYPTO_CMAC) += cmac.o
 obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
 obj-$(CONFIG_CRYPTO_KDF) += kdf.o
+obj-$(CONFIG_CRYPTO_HKDF) += hkdf.o
 obj-$(CONFIG_CRYPTO_VMAC) += vmac.o
 obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
 obj-$(CONFIG_CRYPTO_NULL2) += crypto_null.o
diff --git a/crypto/hkdf.c b/crypto/hkdf.c
new file mode 100644
index 000000000000..35a975ed64a8
--- /dev/null
+++ b/crypto/hkdf.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * RFC 5869 Key-derivation function
+ *
+ * Copyright (C) 2019, Stephan Mueller <smueller@chronox.de>
+ */
+
+/*
+ * The HKDF extract phase is applied with crypto_rng_reset().
+ * The HKDF expand phase is applied with crypto_rng_generate().
+ *
+ * NOTE: In-place cipher operations are not supported.
+ */
+
+#include <linux/module.h>
+#include <crypto/rng.h>
+#include <crypto/internal/rng.h>
+#include <crypto/hash.h>
+#include <crypto/internal/hash.h>
+#include <linux/rtnetlink.h>
+
+struct crypto_hkdf_ctx {
+	struct crypto_shash *extract_kmd;
+	struct crypto_shash *expand_kmd;
+};
+
+#define CRYPTO_HKDF_MAX_DIGESTSIZE	64
+
+/*
+ * HKDF expand phase
+ */
+static int crypto_hkdf_random(struct crypto_rng *rng,
+			      const u8 *info, unsigned int infolen,
+			      u8 *dst, unsigned int dlen)
+{
+	struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	struct crypto_shash *expand_kmd = ctx->expand_kmd;
+	SHASH_DESC_ON_STACK(desc, expand_kmd);
+	unsigned int h = crypto_shash_digestsize(expand_kmd);
+	int err = 0;
+	u8 *dst_orig = dst;
+	const u8 *prev = NULL;
+	uint8_t ctr = 0x01;
+
+	if (dlen > h * 255)
+		return -EINVAL;
+
+	desc->tfm = expand_kmd;
+	desc->flags = crypto_shash_get_flags(expand_kmd) &
+		      CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	/* T(1) and following */
+	while (dlen) {
+		err = crypto_shash_init(desc);
+		if (err)
+			goto out;
+
+		if (prev) {
+			err = crypto_shash_update(desc, prev, h);
+			if (err)
+				goto out;
+		}
+
+		if (info) {
+			err = crypto_shash_update(desc, info, infolen);
+			if (err)
+				goto out;
+		}
+
+		if (dlen < h) {
+			u8 tmpbuffer[CRYPTO_HKDF_MAX_DIGESTSIZE];
+
+			err = crypto_shash_finup(desc, &ctr, 1, tmpbuffer);
+			if (err)
+				goto out;
+			memcpy(dst, tmpbuffer, dlen);
+			memzero_explicit(tmpbuffer, h);
+			goto out;
+		} else {
+			err = crypto_shash_finup(desc, &ctr, 1, dst);
+			if (err)
+				goto out;
+
+			prev = dst;
+			dst += h;
+			dlen -= h;
+			ctr++;
+		}
+	}
+
+out:
+	if (err)
+		memzero_explicit(dst_orig, dlen);
+	shash_desc_zero(desc);
+	return err;
+}
+
+/*
+ * HKDF extract phase.
+ *
+ * The seed is defined to be a concatenation of the salt and the IKM.
+ * The data buffer is pre-pended by an rtattr which provides an u32 value
+ * with the length of the salt. Thus, the buffer length - salt length is the
+ * IKM length.
+ */
+static int crypto_hkdf_seed(struct crypto_rng *rng,
+			    const u8 *seed, unsigned int slen)
+{
+	struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	struct crypto_shash *extract_kmd = ctx->extract_kmd;
+	struct crypto_shash *expand_kmd = ctx->expand_kmd;
+	struct rtattr *rta = (struct rtattr *)seed;
+	SHASH_DESC_ON_STACK(desc, extract_kmd);
+	u32 saltlen;
+	unsigned int h = crypto_shash_digestsize(extract_kmd);
+	int err;
+	const uint8_t null_salt[CRYPTO_HKDF_MAX_DIGESTSIZE] = { 0 };
+	u8 prk[CRYPTO_HKDF_MAX_DIGESTSIZE] = { 0 };
+
+	/* Require aligned buffer to directly read out saltlen below */
+	if (WARN_ON((unsigned long)seed & (sizeof(saltlen) - 1)))
+		return -EINVAL;
+
+	if (!RTA_OK(rta, slen))
+		return -EINVAL;
+	if (rta->rta_type != 1)
+		return -EINVAL;
+	if (RTA_PAYLOAD(rta) < sizeof(saltlen))
+		return -EINVAL;
+	saltlen = *((u32 *)RTA_DATA(rta));
+
+	seed += RTA_ALIGN(rta->rta_len);
+	slen -= RTA_ALIGN(rta->rta_len);
+
+	if (slen < saltlen)
+		return -EINVAL;
+
+	desc->tfm = extract_kmd;
+
+	/* Set the salt as HMAC key */
+	if (saltlen)
+		err = crypto_shash_setkey(extract_kmd, seed, saltlen);
+	else
+		err = crypto_shash_setkey(extract_kmd, null_salt, h);
+	if (err)
+		return err;
+
+	/* Extract the PRK */
+	err = crypto_shash_digest(desc, seed + saltlen, slen - saltlen, prk);
+	if (err)
+		goto err;
+
+	/* Set the PRK for the expand phase */
+	err = crypto_shash_setkey(expand_kmd, prk, h);
+	if (err)
+		goto err;
+
+err:
+	shash_desc_zero(desc);
+	memzero_explicit(prk, h);
+	return err;
+}
+
+static int crypto_hkdf_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+	struct crypto_shash_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_shash *extract_kmd = NULL, *expand_kmd = NULL;
+	unsigned int ds;
+
+	extract_kmd = crypto_spawn_shash(spawn);
+	if (IS_ERR(extract_kmd))
+		return PTR_ERR(extract_kmd);
+
+	expand_kmd = crypto_spawn_shash(spawn);
+	if (IS_ERR(expand_kmd)) {
+		crypto_free_shash(extract_kmd);
+		return PTR_ERR(expand_kmd);
+	}
+
+	ds = crypto_shash_digestsize(extract_kmd);
+	/* Hashes with no digest size are not allowed for KDFs. */
+	if (!ds || ds > CRYPTO_HKDF_MAX_DIGESTSIZE) {
+		crypto_free_shash(extract_kmd);
+		crypto_free_shash(expand_kmd);
+		return -EOPNOTSUPP;
+	}
+
+	ctx->extract_kmd = extract_kmd;
+	ctx->expand_kmd = expand_kmd;
+
+	return 0;
+}
+
+static void crypto_hkdf_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_shash(ctx->extract_kmd);
+	crypto_free_shash(ctx->expand_kmd);
+}
+
+static void crypto_kdf_free(struct rng_instance *inst)
+{
+	crypto_drop_spawn(rng_instance_ctx(inst));
+	kfree(inst);
+}
+
+static int crypto_hkdf_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+	struct rng_instance *inst;
+	struct crypto_alg *alg;
+	struct shash_alg *salg;
+	int err;
+	unsigned int ds, ss;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_RNG);
+	if (err)
+		return err;
+
+	salg = shash_attr_alg(tb[1], 0, 0);
+	if (IS_ERR(salg))
+		return PTR_ERR(salg);
+
+	ds = salg->digestsize;
+	ss = salg->statesize;
+	alg = &salg->base;
+
+	inst = rng_alloc_instance("hkdf", alg);
+	err = PTR_ERR(inst);
+	if (IS_ERR(inst))
+		goto out_put_alg;
+
+	err = crypto_init_shash_spawn(rng_instance_ctx(inst), salg,
+				      rng_crypto_instance(inst));
+	if (err)
+		goto out_free_inst;
+
+	inst->alg.base.cra_priority	= alg->cra_priority;
+	inst->alg.base.cra_blocksize	= alg->cra_blocksize;
+	inst->alg.base.cra_alignmask	= alg->cra_alignmask;
+
+	inst->alg.generate		= crypto_hkdf_random;
+	inst->alg.seed			= crypto_hkdf_seed;
+	inst->alg.seedsize		= ds;
+
+	inst->alg.base.cra_init		= crypto_hkdf_init_tfm;
+	inst->alg.base.cra_exit		= crypto_hkdf_exit_tfm;
+	inst->alg.base.cra_ctxsize	= ALIGN(sizeof(struct crypto_hkdf_ctx) +
+					  ss * 2, crypto_tfm_ctx_alignment());
+
+	inst->free			= crypto_kdf_free;
+
+	err = rng_register_instance(tmpl, inst);
+
+	if (err) {
+out_free_inst:
+		crypto_kdf_free(inst);
+	}
+
+out_put_alg:
+	crypto_mod_put(alg);
+	return err;
+}
+
+static struct crypto_template crypto_hkdf_tmpl = {
+	.name = "hkdf",
+	.create = crypto_hkdf_create,
+	.module = THIS_MODULE,
+};
+
+static int __init crypto_hkdf_init(void)
+{
+	return crypto_register_template(&crypto_hkdf_tmpl);
+}
+
+static void __exit crypto_hkdf_exit(void)
+{
+	crypto_unregister_template(&crypto_hkdf_tmpl);
+}
+
+module_init(crypto_hkdf_init);
+module_exit(crypto_hkdf_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("Key Derivation Function according to RFC 5869");
+MODULE_ALIAS_CRYPTO("hkdf");
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 5/6] crypto: hkdf - add known answer tests
  2019-01-11 19:08     ` [PATCH 0/6] General Key Derivation Function Support Stephan Müller
                         ` (3 preceding siblings ...)
  2019-01-11 19:10       ` [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function Stephan Müller
@ 2019-01-11 19:10       ` Stephan Müller
  2019-01-12  5:19         ` Eric Biggers
  2019-01-11 19:11       ` [PATCH 6/6] crypto: tcrypt - add KDF test invocation Stephan Müller
  2019-01-16 11:06       ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Müller
  6 siblings, 1 reply; 36+ messages in thread
From: Stephan Müller @ 2019-01-11 19:10 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Add known answer tests to the testmgr for the HKDF (RFC5869) cipher.

The known answer tests are derived from RFC 5869 appendix A.

Note, the HKDF is considered to be a FIPS 140-2 allowed (not approved)
cipher as of now. Yet, an allowed cipher is usable under FIPS 140-2
rules.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/testmgr.c |  32 +++++++++++++
 crypto/testmgr.h | 115 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 147 insertions(+)

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index ff9051bffa1f..aba7a3645293 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -3187,6 +3187,38 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.suite = {
 			.hash = __VECS(ghash_tv_template)
 		}
+	}, {
+		.alg = "hkdf(hmac(sha1))",
+		.test = alg_test_kdf,
+		.fips_allowed = 1,
+		.suite = {
+			.kdf = {
+				.vecs = hkdf_hmac_sha1_tv_template,
+				.count = ARRAY_SIZE(hkdf_hmac_sha1_tv_template)
+			}
+		}
+	}, {
+		.alg = "hkdf(hmac(sha224))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "hkdf(hmac(sha256))",
+		.test = alg_test_kdf,
+		.fips_allowed = 1,
+		.suite = {
+			.kdf = {
+				.vecs = hkdf_hmac_sha256_tv_template,
+				.count = ARRAY_SIZE(hkdf_hmac_sha256_tv_template)
+			}
+		}
+	}, {
+		.alg = "hkdf(hmac(sha384))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "hkdf(hmac(sha512))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
 	}, {
 		.alg = "hmac(md5)",
 		.test = alg_test_hash,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index a729b66f8757..7c4aa694e0f3 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -28002,6 +28002,121 @@ static struct kdf_testvec kdf_dpi_hmac_sha256_tv_template[] = {
 	}
 };
 
+/* Test vectors from RFC 5869 appendix A */
+static struct kdf_testvec hkdf_hmac_sha256_tv_template[] = {
+	{
+		.K1 = (unsigned char *)
+#ifdef __LITTLE_ENDIAN
+			"\x08\x00"			/* rta length */
+			"\x01\x00"			/* rta type */
+			"\x0d\x00\x00\x00"		/* salt length */
+#else
+			"\x00\x08"			/* rta length */
+			"\x00\x01"			/* rta type */
+			"\x00\x00\x00\x0d"		/* salt length */
+#endif
+			"\x00\x01\x02\x03\x04\x05\x06\x07"
+			"\x08\x09\x0a\x0b\x0c"		/* salt */
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b",	/* IKM */
+		.K1len = 43,
+		.context = (unsigned char *)
+			"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			"\xf8\xf9",
+		.contextlen = 10,
+		.expected = (unsigned char *)
+			"\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a"
+			"\x90\x43\x4f\x64\xd0\x36\x2f\x2a"
+			"\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c"
+			"\x5d\xb0\x2d\x56\xec\xc4\xc5\xbf"
+			"\x34\x00\x72\x08\xd5\xb8\x87\x18"
+			"\x58\x65",
+		.expectedlen = 42
+	}, {
+		.K1 = (unsigned char *)
+#ifdef __LITTLE_ENDIAN
+			"\x08\x00"			/* rta length */
+			"\x01\x00"			/* rta type */
+#else
+			"\x00\x08"			/* rta length */
+			"\x00\x01"			/* rta type */
+#endif
+			"\x00\x00\x00\x00"		/* salt length */
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b",	/* IKM */
+		.K1len = 30,
+		.context = NULL,
+		.contextlen = 0,
+		.expected = (unsigned char *)
+			"\x8d\xa4\xe7\x75\xa5\x63\xc1\x8f"
+			"\x71\x5f\x80\x2a\x06\x3c\x5a\x31"
+			"\xb8\xa1\x1f\x5c\x5e\xe1\x87\x9e"
+			"\xc3\x45\x4e\x5f\x3c\x73\x8d\x2d"
+			"\x9d\x20\x13\x95\xfa\xa4\xb6\x1a"
+			"\x96\xc8",
+		.expectedlen = 42
+	}
+};
+
+/* Test vectors from RFC 5869 appendix A */
+static struct kdf_testvec hkdf_hmac_sha1_tv_template[] = {
+	{
+		.K1 = (unsigned char *)
+#ifdef __LITTLE_ENDIAN
+			"\x08\x00"			/* rta length */
+			"\x01\x00"			/* rta type */
+			"\x0d\x00\x00\x00"		/* salt length */
+#else
+			"\x00\x08"			/* rta length */
+			"\x00\x01"			/* rta type */
+			"\x00\x00\x00\x0d"		/* salt length */
+#endif
+			"\x00\x01\x02\x03\x04\x05\x06\x07"
+			"\x08\x09\x0a\x0b\x0c"		/* salt */
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b",			/* IKM */
+		.K1len = 32,
+		.context = (unsigned char *)
+			"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			"\xf8\xf9",
+		.contextlen = 10,
+		.expected = (unsigned char *)
+			"\x08\x5a\x01\xea\x1b\x10\xf3\x69"
+			"\x33\x06\x8b\x56\xef\xa5\xad\x81"
+			"\xa4\xf1\x4b\x82\x2f\x5b\x09\x15"
+			"\x68\xa9\xcd\xd4\xf1\x55\xfd\xa2"
+			"\xc2\x2e\x42\x24\x78\xd3\x05\xf3"
+			"\xf8\x96",
+		.expectedlen = 42
+	}, {
+		.K1 = (unsigned char *)
+#ifdef __LITTLE_ENDIAN
+			"\x08\x00"			/* rta length */
+			"\x01\x00"			/* rta type */
+#else
+			"\x00\x08"			/* rta length */
+			"\x00\x01"			/* rta type */
+#endif
+			"\x00\x00\x00\x00"		/* salt length */
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b",	/* IKM */
+		.K1len = 30,
+		.context = NULL,
+		.contextlen = 0,
+		.expected = (unsigned char *)
+			"\x0a\xc1\xaf\x70\x02\xb3\xd7\x61"
+			"\xd1\xe5\x52\x98\xda\x9d\x05\x06"
+			"\xb9\xae\x52\x05\x72\x20\xa3\x06"
+			"\xe0\x7b\x6b\x87\xe8\xdf\x21\xd0"
+			"\xea\x00\x03\x3d\xe0\x39\x84\xd3"
+			"\x49\x18",
+		.expectedlen = 42
+	}
+};
+
 /* Cast5 test vectors from RFC 2144 */
 static const struct cipher_testvec cast5_tv_template[] = {
 	{
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 6/6] crypto: tcrypt - add KDF test invocation
  2019-01-11 19:08     ` [PATCH 0/6] General Key Derivation Function Support Stephan Müller
                         ` (4 preceding siblings ...)
  2019-01-11 19:10       ` [PATCH 5/6] crypto: hkdf - add known answer tests Stephan Müller
@ 2019-01-11 19:11       ` Stephan Müller
  2019-01-16 11:06       ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Müller
  6 siblings, 0 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-11 19:11 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Enable testing of the SP800-108 and RFC5869 KDFs.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/tcrypt.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index e7fb87e114a5..5606e59e80ec 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -2054,6 +2054,14 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
 		ret += tcrypt_test("cbc(sm4)");
 		ret += tcrypt_test("ctr(sm4)");
 		break;
+	case 192:
+		ret += tcrypt_test("kdf_ctr(hmac(sha256))");
+		ret += tcrypt_test("kdf_dpi(hmac(sha256))");
+		ret += tcrypt_test("kdf_fb(hmac(sha256))");
+		break;
+	case 193:
+		ret += tcrypt_test("hkdf(hmac(sha256))");
+		break;
 	case 200:
 		test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
 				speed_template_16_24_32);
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function
  2019-01-11 19:10       ` [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function Stephan Müller
@ 2019-01-12  5:12         ` Eric Biggers
  2019-01-12  9:55           ` Herbert Xu
  2019-01-14  9:30           ` Stephan Müller
  0 siblings, 2 replies; 36+ messages in thread
From: Eric Biggers @ 2019-01-12  5:12 UTC (permalink / raw)
  To: Stephan Müller
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Hi Stephan,

On Fri, Jan 11, 2019 at 08:10:39PM +0100, Stephan Müller wrote:
> The RFC5869 compliant Key Derivation Function is implemented as a
> random number generator considering that it behaves like a deterministic
> RNG.
> 

Thanks for the proof of concept!  I guess it ended up okay.  But can you explain
more the benefits of using the crypto_rng interface, as opposed to just some
crypto_hkdf_*() helper functions that are exported for modules to use?

> The extract and expand phases use different instances of the underlying
> keyed message digest cipher to ensure that while the extraction phase
> generates a new key for the expansion phase, the cipher for the
> expansion phase can still be used. This approach is intended to aid
> multi-threaded uses cases.

I think you partially misunderstood what I was asking for.  One HMAC tfm is
sufficient as long as HKDF-Expand is separated from HKDF-Extract, which you've
done.  So just use one HMAC tfm, and in crypto_hkdf_seed() key it with the
'salt', and then afterwards with the 'prk'.

Also everywhere in this patchset, please avoid using the word "cipher" to refer
to algorithms that are not encryption/decryption.  I know a lot of the crypto
API docs do this, but I think it is a mistake and confusing.  Hash algorithms
and KDFs are not "ciphers".

> 
> Signed-off-by: Stephan Mueller <smueller@chronox.de>
> ---
>  crypto/Kconfig  |   6 +
>  crypto/Makefile |   1 +
>  crypto/hkdf.c   | 290 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 297 insertions(+)
>  create mode 100644 crypto/hkdf.c
> 
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index cc80d89e0cf5..0eee5e129fa3 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -568,6 +568,12 @@ config CRYPTO_KDF
>  	  Support for KDF compliant to SP800-108. All three types of
>  	  KDF specified in SP800-108 are implemented.
>  
> +config CRYPTO_HKDF
> +	tristate "HMAC-based Extract-and expand Key Derivation Function"
> +	select CRYPTO_RNG
> +	help
> +	  Support for KDF compliant to RFC5869.
> +

Make the description
"HMAC-based Extract-and-Expand Key Derivation Function (HKDF)"?
There is a missing dash, and probably the acronym "HKDF" should be in there.

>  config CRYPTO_XCBC
>  	tristate "XCBC support"
>  	select CRYPTO_HASH
> diff --git a/crypto/Makefile b/crypto/Makefile
> index 69a0bb64b0ac..6bbb0a4dea13 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -59,6 +59,7 @@ crypto_user-$(CONFIG_CRYPTO_STATS) += crypto_user_stat.o
>  obj-$(CONFIG_CRYPTO_CMAC) += cmac.o
>  obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
>  obj-$(CONFIG_CRYPTO_KDF) += kdf.o
> +obj-$(CONFIG_CRYPTO_HKDF) += hkdf.o
>  obj-$(CONFIG_CRYPTO_VMAC) += vmac.o
>  obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
>  obj-$(CONFIG_CRYPTO_NULL2) += crypto_null.o
> diff --git a/crypto/hkdf.c b/crypto/hkdf.c
> new file mode 100644
> index 000000000000..35a975ed64a8
> --- /dev/null
> +++ b/crypto/hkdf.c
> @@ -0,0 +1,290 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +/*
> + * RFC 5869 Key-derivation function
> + *

People don't know what RFC xyz is.  Please be more explicit than just the RFC
number, e.g.

"HKDF: HMAC-based Extract-and-Expand Key Derivation Function (RFC 5869)"

> + * Copyright (C) 2019, Stephan Mueller <smueller@chronox.de>
> + */
> +
> +/*
> + * The HKDF extract phase is applied with crypto_rng_reset().
> + * The HKDF expand phase is applied with crypto_rng_generate().
> + *
> + * NOTE: In-place cipher operations are not supported.
> + */

What does an "in-place cipher operation" mean in this context?  That the 'info'
buffer must not overlap the 'dst' buffer?  Maybe crypto_rng_generate() should
check that for all crypto_rngs?  Or is it different for different crypto_rngs?

> +
> +#include <linux/module.h>
> +#include <crypto/rng.h>
> +#include <crypto/internal/rng.h>
> +#include <crypto/hash.h>
> +#include <crypto/internal/hash.h>
> +#include <linux/rtnetlink.h>
> +
> +struct crypto_hkdf_ctx {
> +	struct crypto_shash *extract_kmd;
> +	struct crypto_shash *expand_kmd;
> +};
> +
> +#define CRYPTO_HKDF_MAX_DIGESTSIZE	64
> +
> +/*
> + * HKDF expand phase
> + */
> +static int crypto_hkdf_random(struct crypto_rng *rng,
> +			      const u8 *info, unsigned int infolen,
> +			      u8 *dst, unsigned int dlen)

Why call it crypto_hkdf_random() instead of crypto_hkdf_generate()?  The latter
would match rng_alg::generate.

> +{
> +	struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));

const

> +	struct crypto_shash *expand_kmd = ctx->expand_kmd;
> +	SHASH_DESC_ON_STACK(desc, expand_kmd);

> +	unsigned int h = crypto_shash_digestsize(expand_kmd);

const

> +	int err = 0;
> +	u8 *dst_orig = dst;
> +	const u8 *prev = NULL;

> +	uint8_t ctr = 0x01;

u8 instead of uint8_t

> +
> +	if (dlen > h * 255)
> +		return -EINVAL;
> +
> +	desc->tfm = expand_kmd;

> +	desc->flags = crypto_shash_get_flags(expand_kmd) &
> +		      CRYPTO_TFM_REQ_MAY_SLEEP;

This line setting desc->flags doesn't make sense.  How is the user meant to
control whether crypto_rng_generate() can sleep or not?  Or can it always sleep?
Either way this part is wrong since the user can't get access to the HMAC tfm to
set this flag being checked for.

> +
> +	/* T(1) and following */
> +	while (dlen) {
> +		err = crypto_shash_init(desc);
> +		if (err)
> +			goto out;
> +
> +		if (prev) {
> +			err = crypto_shash_update(desc, prev, h);
> +			if (err)
> +				goto out;
> +		}
> +
> +		if (info) {
> +			err = crypto_shash_update(desc, info, infolen);
> +			if (err)
> +				goto out;
> +		}
> +
> +		if (dlen < h) {
> +			u8 tmpbuffer[CRYPTO_HKDF_MAX_DIGESTSIZE];
> +
> +			err = crypto_shash_finup(desc, &ctr, 1, tmpbuffer);
> +			if (err)
> +				goto out;
> +			memcpy(dst, tmpbuffer, dlen);
> +			memzero_explicit(tmpbuffer, h);
> +			goto out;
> +		} else {

No need for the 'else'.

> +			err = crypto_shash_finup(desc, &ctr, 1, dst);
> +			if (err)
> +				goto out;
> +
> +			prev = dst;
> +			dst += h;
> +			dlen -= h;
> +			ctr++;
> +		}
> +	}
> +
> +out:
> +	if (err)
> +		memzero_explicit(dst_orig, dlen);
> +	shash_desc_zero(desc);
> +	return err;
> +}
> +
> +/*
> + * HKDF extract phase.
> + *
> + * The seed is defined to be a concatenation of the salt and the IKM.
> + * The data buffer is pre-pended by an rtattr which provides an u32 value
> + * with the length of the salt. Thus, the buffer length - salt length is the
> + * IKM length.
> + */
> +static int crypto_hkdf_seed(struct crypto_rng *rng,
> +			    const u8 *seed, unsigned int slen)
> +{
> +	struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));

const

> +	struct crypto_shash *extract_kmd = ctx->extract_kmd;
> +	struct crypto_shash *expand_kmd = ctx->expand_kmd;
> +	struct rtattr *rta = (struct rtattr *)seed;
> +	SHASH_DESC_ON_STACK(desc, extract_kmd);
> +	u32 saltlen;
> +	unsigned int h = crypto_shash_digestsize(extract_kmd);
> +	int err;
> +	const uint8_t null_salt[CRYPTO_HKDF_MAX_DIGESTSIZE] = { 0 };

static const

> +	u8 prk[CRYPTO_HKDF_MAX_DIGESTSIZE] = { 0 };

No need to initialize this.

> +
> +	/* Require aligned buffer to directly read out saltlen below */
> +	if (WARN_ON((unsigned long)seed & (sizeof(saltlen) - 1)))
> +		return -EINVAL;
> +
> +	if (!RTA_OK(rta, slen))
> +		return -EINVAL;
> +	if (rta->rta_type != 1)
> +		return -EINVAL;
> +	if (RTA_PAYLOAD(rta) < sizeof(saltlen))
> +		return -EINVAL;
> +	saltlen = *((u32 *)RTA_DATA(rta));

I'm guessing you copied the weird "length as a rtattr payload" approach from the
authenc template.  I think it's not necessary.  And it's overly error-prone, as
shown by the authenc template getting the parsing wrong for years and you making
the exact same mistake again here...
(See https://patchwork.kernel.org/patch/10732803/)  How about just using a u32
at the beginning without the 'rtattr' preceding it?

Also it should use get_unaligned() so there is no alignment requirement the
caller has to comply with.

> +
> +	seed += RTA_ALIGN(rta->rta_len);
> +	slen -= RTA_ALIGN(rta->rta_len);
> +
> +	if (slen < saltlen)
> +		return -EINVAL;
> +

> +	desc->tfm = extract_kmd;

desc->flags needs to be set.

> +
> +	/* Set the salt as HMAC key */
> +	if (saltlen)
> +		err = crypto_shash_setkey(extract_kmd, seed, saltlen);
> +	else
> +		err = crypto_shash_setkey(extract_kmd, null_salt, h);
> +	if (err)
> +		return err;
> +
> +	/* Extract the PRK */
> +	err = crypto_shash_digest(desc, seed + saltlen, slen - saltlen, prk);
> +	if (err)
> +		goto err;
> +
> +	/* Set the PRK for the expand phase */
> +	err = crypto_shash_setkey(expand_kmd, prk, h);
> +	if (err)
> +		goto err;
> +
> +err:
> +	shash_desc_zero(desc);
> +	memzero_explicit(prk, h);
> +	return err;
> +}
> +
> +static int crypto_hkdf_init_tfm(struct crypto_tfm *tfm)
> +{
> +	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
> +	struct crypto_shash_spawn *spawn = crypto_instance_ctx(inst);
> +	struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(tfm);
> +	struct crypto_shash *extract_kmd = NULL, *expand_kmd = NULL;
> +	unsigned int ds;
> +
> +	extract_kmd = crypto_spawn_shash(spawn);
> +	if (IS_ERR(extract_kmd))
> +		return PTR_ERR(extract_kmd);
> +
> +	expand_kmd = crypto_spawn_shash(spawn);
> +	if (IS_ERR(expand_kmd)) {
> +		crypto_free_shash(extract_kmd);
> +		return PTR_ERR(expand_kmd);
> +	}
> +
> +	ds = crypto_shash_digestsize(extract_kmd);
> +	/* Hashes with no digest size are not allowed for KDFs. */
> +	if (!ds || ds > CRYPTO_HKDF_MAX_DIGESTSIZE) {
> +		crypto_free_shash(extract_kmd);
> +		crypto_free_shash(expand_kmd);
> +		return -EOPNOTSUPP;
> +	}

The digest size should be validated when instantiating the template, not here.

> +
> +	ctx->extract_kmd = extract_kmd;
> +	ctx->expand_kmd = expand_kmd;
> +
> +	return 0;
> +}
> +
> +static void crypto_hkdf_exit_tfm(struct crypto_tfm *tfm)
> +{
> +	struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(tfm);
> +
> +	crypto_free_shash(ctx->extract_kmd);
> +	crypto_free_shash(ctx->expand_kmd);
> +}
> +
> +static void crypto_kdf_free(struct rng_instance *inst)
> +{
> +	crypto_drop_spawn(rng_instance_ctx(inst));
> +	kfree(inst);
> +}
> +
> +static int crypto_hkdf_create(struct crypto_template *tmpl, struct rtattr **tb)
> +{
> +	struct rng_instance *inst;
> +	struct crypto_alg *alg;
> +	struct shash_alg *salg;
> +	int err;
> +	unsigned int ds, ss;
> +
> +	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_RNG);
> +	if (err)
> +		return err;
> +
> +	salg = shash_attr_alg(tb[1], 0, 0);
> +	if (IS_ERR(salg))
> +		return PTR_ERR(salg);
> +
> +	ds = salg->digestsize;
> +	ss = salg->statesize;

I don't see what the 'statesize' is needed for.

> +	alg = &salg->base;

Check here that the underlying algorithm really is "hmac(" something?

Alternatively it may be a good idea to simplify usage by making the template
just take the unkeyed hash directly, like "hkdf(sha512)".  And if any users
really need to specify a specific HMAC implementation then another template
usable as "hkdf_base(hmac(sha512))" could be added later.

> +
> +	inst = rng_alloc_instance("hkdf", alg);
> +	err = PTR_ERR(inst);
> +	if (IS_ERR(inst))
> +		goto out_put_alg;
> +
> +	err = crypto_init_shash_spawn(rng_instance_ctx(inst), salg,
> +				      rng_crypto_instance(inst));
> +	if (err)
> +		goto out_free_inst;

This error path calls crypto_drop_spawn() without a prior successful
crypto_init_spawn().

> +
> +	inst->alg.base.cra_priority	= alg->cra_priority;
> +	inst->alg.base.cra_blocksize	= alg->cra_blocksize;
> +	inst->alg.base.cra_alignmask	= alg->cra_alignmask;
> +
> +	inst->alg.generate		= crypto_hkdf_random;
> +	inst->alg.seed			= crypto_hkdf_seed;
> +	inst->alg.seedsize		= ds;

What does the seedsize mean here, given that crypto_hkdf_seed() actually takes a
variable length seed?

> +
> +	inst->alg.base.cra_init		= crypto_hkdf_init_tfm;
> +	inst->alg.base.cra_exit		= crypto_hkdf_exit_tfm;

> +	inst->alg.base.cra_ctxsize	= ALIGN(sizeof(struct crypto_hkdf_ctx) +
> +					  ss * 2, crypto_tfm_ctx_alignment());

Why isn't this simply sizeof(struct crypto_hkdf_ctx)?

> +
> +	inst->free			= crypto_kdf_free;
> +
> +	err = rng_register_instance(tmpl, inst);
> +
> +	if (err) {
> +out_free_inst:
> +		crypto_kdf_free(inst);
> +	}
> +
> +out_put_alg:
> +	crypto_mod_put(alg);
> +	return err;
> +}
> +
> +static struct crypto_template crypto_hkdf_tmpl = {
> +	.name = "hkdf",
> +	.create = crypto_hkdf_create,
> +	.module = THIS_MODULE,
> +};
> +
> +static int __init crypto_hkdf_init(void)
> +{
> +	return crypto_register_template(&crypto_hkdf_tmpl);
> +}
> +
> +static void __exit crypto_hkdf_exit(void)
> +{
> +	crypto_unregister_template(&crypto_hkdf_tmpl);
> +}
> +
> +module_init(crypto_hkdf_init);
> +module_exit(crypto_hkdf_exit);
> +
> +MODULE_LICENSE("GPL");

MODULE_LICENSE("GPL") means GPLv2+ but the SPDX header says GPLv2 only.

> +MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
> +MODULE_DESCRIPTION("Key Derivation Function according to RFC 5869");

Mention "HKDF" in the module description?

> +MODULE_ALIAS_CRYPTO("hkdf");
> -- 
> 2.20.1

Thanks!

- Eric

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 5/6] crypto: hkdf - add known answer tests
  2019-01-11 19:10       ` [PATCH 5/6] crypto: hkdf - add known answer tests Stephan Müller
@ 2019-01-12  5:19         ` Eric Biggers
  2019-01-14  9:25           ` Stephan Müller
  0 siblings, 1 reply; 36+ messages in thread
From: Eric Biggers @ 2019-01-12  5:19 UTC (permalink / raw)
  To: Stephan Müller
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

On Fri, Jan 11, 2019 at 08:10:56PM +0100, Stephan Müller wrote:
> Add known answer tests to the testmgr for the HKDF (RFC5869) cipher.
> 
> The known answer tests are derived from RFC 5869 appendix A.
> 
> Note, the HKDF is considered to be a FIPS 140-2 allowed (not approved)
> cipher as of now. Yet, an allowed cipher is usable under FIPS 140-2
> rules.
> 
> Signed-off-by: Stephan Mueller <smueller@chronox.de>
> ---
>  crypto/testmgr.c |  32 +++++++++++++
>  crypto/testmgr.h | 115 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 147 insertions(+)
> 
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index ff9051bffa1f..aba7a3645293 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -3187,6 +3187,38 @@ static const struct alg_test_desc alg_test_descs[] = {
>  		.suite = {
>  			.hash = __VECS(ghash_tv_template)
>  		}
> +	}, {
> +		.alg = "hkdf(hmac(sha1))",
> +		.test = alg_test_kdf,
> +		.fips_allowed = 1,
> +		.suite = {
> +			.kdf = {
> +				.vecs = hkdf_hmac_sha1_tv_template,
> +				.count = ARRAY_SIZE(hkdf_hmac_sha1_tv_template)

Use the __VECS() macro.

> +			}
> +		}
> +	}, {
> +		.alg = "hkdf(hmac(sha224))",
> +		.test = alg_test_null,
> +		.fips_allowed = 1,

I think it is dumb to add algorithms to the testmgr with no tests just so the
'fips_allowed' flag can be set.  And doesn't FIPS sometimes require tests
anyway?  I don't think the "null test" should count as a test :-)

Perhaps just include sha256 and sha512, and have tests for them?

> +	}, {
> +		.alg = "hkdf(hmac(sha256))",
> +		.test = alg_test_kdf,
> +		.fips_allowed = 1,
> +		.suite = {
> +			.kdf = {
> +				.vecs = hkdf_hmac_sha256_tv_template,
> +				.count = ARRAY_SIZE(hkdf_hmac_sha256_tv_template)
> +			}
> +		}
> +	}, {
> +		.alg = "hkdf(hmac(sha384))",
> +		.test = alg_test_null,
> +		.fips_allowed = 1,
> +	}, {
> +		.alg = "hkdf(hmac(sha512))",
> +		.test = alg_test_null,
> +		.fips_allowed = 1,
>  	}, {
>  		.alg = "hmac(md5)",
>  		.test = alg_test_hash,
> diff --git a/crypto/testmgr.h b/crypto/testmgr.h
> index a729b66f8757..7c4aa694e0f3 100644
> --- a/crypto/testmgr.h
> +++ b/crypto/testmgr.h
> @@ -28002,6 +28002,121 @@ static struct kdf_testvec kdf_dpi_hmac_sha256_tv_template[] = {
>  	}
>  };
>  
> +/* Test vectors from RFC 5869 appendix A */
> +static struct kdf_testvec hkdf_hmac_sha256_tv_template[] = {

const

Likewise for all other kdf_testvecs.

> +	{
> +		.K1 = (unsigned char *)

No need for this cast if you make the pointers const in struct kdf_testvec.

Likewise for all other testvecs.

> +#ifdef __LITTLE_ENDIAN
> +			"\x08\x00"			/* rta length */
> +			"\x01\x00"			/* rta type */
> +			"\x0d\x00\x00\x00"		/* salt length */
> +#else
> +			"\x00\x08"			/* rta length */
> +			"\x00\x01"			/* rta type */
> +			"\x00\x00\x00\x0d"		/* salt length */
> +#endif
> +			"\x00\x01\x02\x03\x04\x05\x06\x07"
> +			"\x08\x09\x0a\x0b\x0c"		/* salt */
> +			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
> +			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
> +			"\x0b\x0b\x0b\x0b\x0b\x0b",	/* IKM */
> +		.K1len = 43,
> +		.context = (unsigned char *)
> +			"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
> +			"\xf8\xf9",
> +		.contextlen = 10,
> +		.expected = (unsigned char *)
> +			"\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a"
> +			"\x90\x43\x4f\x64\xd0\x36\x2f\x2a"
> +			"\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c"
> +			"\x5d\xb0\x2d\x56\xec\xc4\xc5\xbf"
> +			"\x34\x00\x72\x08\xd5\xb8\x87\x18"
> +			"\x58\x65",
> +		.expectedlen = 42
> +	}, {
> +		.K1 = (unsigned char *)
> +#ifdef __LITTLE_ENDIAN
> +			"\x08\x00"			/* rta length */
> +			"\x01\x00"			/* rta type */
> +#else
> +			"\x00\x08"			/* rta length */
> +			"\x00\x01"			/* rta type */
> +#endif
> +			"\x00\x00\x00\x00"		/* salt length */
> +			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
> +			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
> +			"\x0b\x0b\x0b\x0b\x0b\x0b",	/* IKM */
> +		.K1len = 30,
> +		.context = NULL,
> +		.contextlen = 0,
> +		.expected = (unsigned char *)
> +			"\x8d\xa4\xe7\x75\xa5\x63\xc1\x8f"
> +			"\x71\x5f\x80\x2a\x06\x3c\x5a\x31"
> +			"\xb8\xa1\x1f\x5c\x5e\xe1\x87\x9e"
> +			"\xc3\x45\x4e\x5f\x3c\x73\x8d\x2d"
> +			"\x9d\x20\x13\x95\xfa\xa4\xb6\x1a"
> +			"\x96\xc8",
> +		.expectedlen = 42
> +	}
> +};
> +
> +/* Test vectors from RFC 5869 appendix A */
> +static struct kdf_testvec hkdf_hmac_sha1_tv_template[] = {
> +	{
> +		.K1 = (unsigned char *)
> +#ifdef __LITTLE_ENDIAN
> +			"\x08\x00"			/* rta length */
> +			"\x01\x00"			/* rta type */
> +			"\x0d\x00\x00\x00"		/* salt length */
> +#else
> +			"\x00\x08"			/* rta length */
> +			"\x00\x01"			/* rta type */
> +			"\x00\x00\x00\x0d"		/* salt length */
> +#endif
> +			"\x00\x01\x02\x03\x04\x05\x06\x07"
> +			"\x08\x09\x0a\x0b\x0c"		/* salt */
> +			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
> +			"\x0b\x0b\x0b",			/* IKM */
> +		.K1len = 32,
> +		.context = (unsigned char *)
> +			"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
> +			"\xf8\xf9",
> +		.contextlen = 10,
> +		.expected = (unsigned char *)
> +			"\x08\x5a\x01\xea\x1b\x10\xf3\x69"
> +			"\x33\x06\x8b\x56\xef\xa5\xad\x81"
> +			"\xa4\xf1\x4b\x82\x2f\x5b\x09\x15"
> +			"\x68\xa9\xcd\xd4\xf1\x55\xfd\xa2"
> +			"\xc2\x2e\x42\x24\x78\xd3\x05\xf3"
> +			"\xf8\x96",
> +		.expectedlen = 42
> +	}, {
> +		.K1 = (unsigned char *)
> +#ifdef __LITTLE_ENDIAN
> +			"\x08\x00"			/* rta length */
> +			"\x01\x00"			/* rta type */
> +#else
> +			"\x00\x08"			/* rta length */
> +			"\x00\x01"			/* rta type */
> +#endif
> +			"\x00\x00\x00\x00"		/* salt length */
> +			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
> +			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
> +			"\x0b\x0b\x0b\x0b\x0b\x0b",	/* IKM */
> +		.K1len = 30,
> +		.context = NULL,
> +		.contextlen = 0,
> +		.expected = (unsigned char *)
> +			"\x0a\xc1\xaf\x70\x02\xb3\xd7\x61"
> +			"\xd1\xe5\x52\x98\xda\x9d\x05\x06"
> +			"\xb9\xae\x52\x05\x72\x20\xa3\x06"
> +			"\xe0\x7b\x6b\x87\xe8\xdf\x21\xd0"
> +			"\xea\x00\x03\x3d\xe0\x39\x84\xd3"
> +			"\x49\x18",
> +		.expectedlen = 42
> +	}
> +};
> +
>  /* Cast5 test vectors from RFC 2144 */
>  static const struct cipher_testvec cast5_tv_template[] = {
>  	{
> -- 
> 2.20.1
> 
> 
> 
> 

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 3/6] crypto: kdf - add known answer tests
  2019-01-11 19:10       ` [PATCH 3/6] crypto: kdf - add known answer tests Stephan Müller
@ 2019-01-12  5:26         ` Eric Biggers
  2019-01-14  9:26           ` Stephan Müller
  0 siblings, 1 reply; 36+ messages in thread
From: Eric Biggers @ 2019-01-12  5:26 UTC (permalink / raw)
  To: Stephan Müller
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

On Fri, Jan 11, 2019 at 08:10:22PM +0100, Stephan Müller wrote:
> Add known answer tests to the testmgr for the KDF (SP800-108) cipher.
> 
> Signed-off-by: Stephan Mueller <smueller@chronox.de>
> ---
>  crypto/testmgr.c | 226 +++++++++++++++++++++++++++++++++++++++++++++++
>  crypto/testmgr.h | 110 +++++++++++++++++++++++
>  2 files changed, 336 insertions(+)
> 
> diff --git a/crypto/testmgr.c b/crypto/testmgr.c
> index 0f684a414acb..ff9051bffa1f 100644
> --- a/crypto/testmgr.c
> +++ b/crypto/testmgr.c
> @@ -110,6 +110,11 @@ struct drbg_test_suite {
>  	unsigned int count;
>  };
>  
> +struct kdf_test_suite {
> +	struct kdf_testvec *vecs;
> +	unsigned int count;
> +};
> +
>  struct akcipher_test_suite {
>  	const struct akcipher_testvec *vecs;
>  	unsigned int count;
> @@ -133,6 +138,7 @@ struct alg_test_desc {
>  		struct hash_test_suite hash;
>  		struct cprng_test_suite cprng;
>  		struct drbg_test_suite drbg;
> +		struct kdf_test_suite kdf;
>  		struct akcipher_test_suite akcipher;
>  		struct kpp_test_suite kpp;
>  	} suite;
> @@ -2020,6 +2026,64 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr,
>  	return ret;
>  }
>  
> +static int kdf_cavs_test(struct kdf_testvec *test,
> +			 const char *driver, u32 type, u32 mask)

Why not just "kdf_test()"?

> +{
> +	int ret = -EAGAIN;
> +	struct crypto_rng *drng;
> +	unsigned char *buf = kzalloc(test->expectedlen, GFP_KERNEL);

s/unsigned char/u8

> +
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	drng = crypto_alloc_rng(driver, type | CRYPTO_ALG_INTERNAL, mask);
> +	if (IS_ERR(drng)) {
> +		printk(KERN_ERR "alg: kdf: could not allocate cipher handle "
> +		       "for %s\n", driver);

pr_err

> +		kzfree(buf);

kfree is fine here.

> +		return -ENOMEM;
> +	}
> +
> +	ret = crypto_rng_reset(drng, test->K1, test->K1len);
> +	if (ret) {
> +		printk(KERN_ERR "alg: kdf: could not set key derivation key\n");

pr_err

> +		goto err;
> +	}
> +
> +	ret = crypto_rng_generate(drng, test->context, test->contextlen,
> +				  buf, test->expectedlen);
> +	if (ret) {
> +		printk(KERN_ERR "alg: kdf: could not obtain key data\n");

pr_err

> +		goto err;
> +	}
> +
> +	ret = memcmp(test->expected, buf, test->expectedlen);

Elsewhere this function returns an -errno value but this is different.

> +
> +err:
> +	crypto_free_rng(drng);
> +	kzfree(buf);

kfree would be fine here too.

> +	return ret;
> +}
> +
> +static int alg_test_kdf(const struct alg_test_desc *desc, const char *driver,
> +			u32 type, u32 mask)
> +{
> +	int err = 0;
> +	unsigned int i = 0;
> +	struct kdf_testvec *template = desc->suite.kdf.vecs;

const

- Eric

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 2/6] crypto: kdf - SP800-108 Key Derivation Function
  2019-01-11 19:10       ` [PATCH 2/6] crypto: kdf - SP800-108 Key Derivation Function Stephan Müller
@ 2019-01-12  5:27         ` Eric Biggers
  2019-01-14  9:31           ` Stephan Müller
  0 siblings, 1 reply; 36+ messages in thread
From: Eric Biggers @ 2019-01-12  5:27 UTC (permalink / raw)
  To: Stephan Müller
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

On Fri, Jan 11, 2019 at 08:10:02PM +0100, Stephan Müller wrote:
> The SP800-108 compliant Key Derivation Function is implemented as a
> random number generator considering that it behaves like a deterministic
> RNG.
> 
> All three KDF types specified in SP800-108 are implemented.
> 
> The code comments provide details about how to invoke the different KDF
> types.
> 
> Signed-off-by: Stephan Mueller <smueller@chronox.de>
> ---
>  crypto/Kconfig  |   7 +
>  crypto/Makefile |   1 +
>  crypto/kdf.c    | 492 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 500 insertions(+)
>  create mode 100644 crypto/kdf.c
> 
> diff --git a/crypto/Kconfig b/crypto/Kconfig
> index 86960aa53e0f..cc80d89e0cf5 100644
> --- a/crypto/Kconfig
> +++ b/crypto/Kconfig
> @@ -561,6 +561,13 @@ config CRYPTO_HMAC
>  	  HMAC: Keyed-Hashing for Message Authentication (RFC2104).
>  	  This is required for IPSec.
>  
> +config CRYPTO_KDF
> +	tristate "Key Derivation Function (SP800-108)"
> +	select CRYPTO_RNG
> +	help
> +	  Support for KDF compliant to SP800-108. All three types of
> +	  KDF specified in SP800-108 are implemented.
> +
>  config CRYPTO_XCBC
>  	tristate "XCBC support"
>  	select CRYPTO_HASH
> diff --git a/crypto/Makefile b/crypto/Makefile
> index 799ed5e94606..69a0bb64b0ac 100644
> --- a/crypto/Makefile
> +++ b/crypto/Makefile
> @@ -58,6 +58,7 @@ crypto_user-y := crypto_user_base.o
>  crypto_user-$(CONFIG_CRYPTO_STATS) += crypto_user_stat.o
>  obj-$(CONFIG_CRYPTO_CMAC) += cmac.o
>  obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
> +obj-$(CONFIG_CRYPTO_KDF) += kdf.o

This naming is too generic.  CONFIG_CRYPTO_KDF and kdf.c imply that this is
related to all KDFs.  But actually it is an implementation of a few specific
KDFs.  Can you give it a clearer name, like KDF_SP800?

- Eric

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function
  2019-01-12  5:12         ` Eric Biggers
@ 2019-01-12  9:55           ` Herbert Xu
  2019-01-13  7:56             ` Stephan Müller
  2019-01-14  9:30           ` Stephan Müller
  1 sibling, 1 reply; 36+ messages in thread
From: Herbert Xu @ 2019-01-12  9:55 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Stephan Müller, James Bottomley, Andy Lutomirski, Lee,
	Chun-Yi, Rafael J . Wysocki, Pavel Machek, linux-kernel,
	linux-pm, keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum,
	Ryan Chen, David Howells, Giovanni Gherdovich, Randy Dunlap,
	Jann Horn, Andy Lutomirski, linux-crypto

On Fri, Jan 11, 2019 at 09:12:54PM -0800, Eric Biggers wrote:
> Hi Stephan,
> 
> On Fri, Jan 11, 2019 at 08:10:39PM +0100, Stephan Müller wrote:
> > The RFC5869 compliant Key Derivation Function is implemented as a
> > random number generator considering that it behaves like a deterministic
> > RNG.
> > 
> 
> Thanks for the proof of concept!  I guess it ended up okay.  But can you explain
> more the benefits of using the crypto_rng interface, as opposed to just some
> crypto_hkdf_*() helper functions that are exported for modules to use?

I agree.  I see no benefit in adding this through the RNG API as
opposed to just providing it as a helper.  If some form of hardware
acceleration were to eventuate in the future we could always revisit
this.

Cheers,
-- 
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] 36+ messages in thread

* Re: [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function
  2019-01-12  9:55           ` Herbert Xu
@ 2019-01-13  7:56             ` Stephan Müller
  2019-01-13 16:52               ` James Bottomley
  0 siblings, 1 reply; 36+ messages in thread
From: Stephan Müller @ 2019-01-13  7:56 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Am Samstag, 12. Januar 2019, 10:55:35 CET schrieb Herbert Xu:

Hi Herbert,

> On Fri, Jan 11, 2019 at 09:12:54PM -0800, Eric Biggers wrote:
> > Hi Stephan,
> > 
> > On Fri, Jan 11, 2019 at 08:10:39PM +0100, Stephan Müller wrote:
> > > The RFC5869 compliant Key Derivation Function is implemented as a
> > > random number generator considering that it behaves like a deterministic
> > > RNG.
> > 
> > Thanks for the proof of concept!  I guess it ended up okay.  But can you
> > explain more the benefits of using the crypto_rng interface, as opposed
> > to just some crypto_hkdf_*() helper functions that are exported for
> > modules to use?
> I agree.  I see no benefit in adding this through the RNG API as
> opposed to just providing it as a helper.  If some form of hardware
> acceleration were to eventuate in the future we could always revisit
> this.

The advantages for using the kernel crypto API to add KDFs as opposed to 
adding helper wrappers are the following in my view:

- employment of the kernel crypto API testmgr - invocation of the testmgr is 
transparent and thus already provided without any additional code to link to 
it

- FIPS 140-2 compliance: To mark a KDF as FIPS 140-2 approved cipher, it must 
be subject to a known-answer self test (implemented by the testmgr) as well as 
to an enforcement of the integrity check verification. In FIPS 140-2 mode, the 
kernel crypto API panic()s when a kernel crypto API module is loaded and its 
signature does not check out. As this is only relevant for crypto modules (and 
not arbitrary other kernel modules), this is implemented with the invocations 
the crypto_register_alg as well as crypto_register_template functions. Thus, 
when using a wrapper code to implement the KDF, they can per definition not be 
FIPS 140-2 approved.

- The invoker of a KDF has one consistent API. This implies that the KDF 
selection now becomes more of a "configuration" choice. For example, when you 
look at the KDF use case for the keys subsystem (security/keys/dh.c), 
selecting the type of KDF would only necessitate a change of a string 
referencing the KDF. A lot of people somehow favor the extract-and-expand KDFs 
over the traditional KDFs. Now, that the RFC5869 HKDF is also approved as per 
SP800-56A rev3, I could see that folks may want to switch to HKDF for the key 
management. When we have a common API, this choice could even be left to the 
caller.

The question may arise why to plug the KDFs into RNGs. The answer is quite 
simple: KDFs are a form of random number generator. In that they take some 
input for initialization (aka seed, salt, key, personalization string). Then 
they produce pseudo-random bit sequences of arbitrary length. Possibly the 
generation operation can be modified by providing some additional input to be 
used by the generation process (aka label, context, info string, additional 
information string). Thus, the RNG interface is a natural fit for the KDFs.

Ciao
Stephan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function
  2019-01-13  7:56             ` Stephan Müller
@ 2019-01-13 16:52               ` James Bottomley
  0 siblings, 0 replies; 36+ messages in thread
From: James Bottomley @ 2019-01-13 16:52 UTC (permalink / raw)
  To: Stephan Müller, Herbert Xu
  Cc: Eric Biggers, Andy Lutomirski, Lee, Chun-Yi, Rafael J . Wysocki,
	Pavel Machek, linux-kernel, linux-pm, keyrings,
	Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

On Sun, 2019-01-13 at 08:56 +0100, Stephan Müller wrote:
> The question may arise why to plug the KDFs into RNGs. The answer is
> quite simple: KDFs are a form of random number generator. In that
> they take some input for initialization (aka seed, salt, key,
> personalization string). Then they produce pseudo-random bit
> sequences of arbitrary length. Possibly the generation operation can
> be modified by providing some additional input to be used by the
> generation process (aka label, context, info string, additional 
> information string). Thus, the RNG interface is a natural fit for the
> KDFs.

Philosophically, that's quite wrong.  KDFs are a class of pseudorandom
functions (PRFs).  PRFs are designed so that the output is
indistinguishable from a random number generator to observers who don't
know the input but is deterministically useful for participants who do.
 That means the're definitely not RNGs they're functions whose output
is designed to look like the output of an RNG.

I suppose the mathematical thing that distinguishes PRFs and RNGs is
entropy: PRFs have zero entropy because given the same inputs you
expect the same output. Now whether it makes sense to use the RNG API
or not I'll leave that up to the crypto people.  I would have expected
any cryptographic RNG API to be mostly about entropy management (the
Linux core internal one certainly is), but it appears that the one in
crypto isn't.

James

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 5/6] crypto: hkdf - add known answer tests
  2019-01-12  5:19         ` Eric Biggers
@ 2019-01-14  9:25           ` Stephan Müller
  2019-01-14 17:44             ` Eric Biggers
  0 siblings, 1 reply; 36+ messages in thread
From: Stephan Müller @ 2019-01-14  9:25 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Am Samstag, 12. Januar 2019, 06:19:15 CET schrieb Eric Biggers:

Hi Eric,

[...]
> 
> > +			}
> > +		}
> > +	}, {
> > +		.alg = "hkdf(hmac(sha224))",
> > +		.test = alg_test_null,
> > +		.fips_allowed = 1,
> 
> I think it is dumb to add algorithms to the testmgr with no tests just so
> the 'fips_allowed' flag can be set. 

Currently it is the only way. But I agree that it could be done better.

> And doesn't FIPS sometimes require
> tests anyway?  I don't think the "null test" should count as a test :-)

Yes, it DOES count as a test (as strange as it may sound)! :-)

The FIPS requirements are as follows:

- raw ciphers must be subject to a FIPS test with one block chaining mode to 
cover that cipher with all block chaining modes (e.g. you can test ecb(aes) to 
cover AES with *all* existing block chaining modes).

- for compound crypto algorithm (like RSA with respect to hashes, KDF with 
respect to the keyed message digest, HMAC with respect to hashes), the 
wrapping crypto algorithm needs to be tested with *one* wrapped cipher at 
least (but also not more. E.g. if you have a self test for, say, all SHA-1 and 
SHA-2, you only need one HMAC SHA test or one KDF HMAC SHA test.

- in some circumstances, it is even permissible to test wrapping crypto 
algorithms where the underlying algo is implicitly tested. E.g. if you have a 
HMAC SHA-256 test, you do not need an individual SHA-256 test.


> 
> Perhaps just include sha256 and sha512, and have tests for them?

Do you happen to have an official SHA-512 HKDF test vector? RFC5869 only has 
SHA-1 and SHA-256 tests.
> 

[...]
> > 
> > +/* Test vectors from RFC 5869 appendix A */
> > +static struct kdf_testvec hkdf_hmac_sha256_tv_template[] = {
> 
> const
> 
> Likewise for all other kdf_testvecs.

const does not work with __VECS :-(

I leave it without const at the moment. I think the __VECS should be updated 
along with all test vectors.

[...]

Ciao
Stephan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 3/6] crypto: kdf - add known answer tests
  2019-01-12  5:26         ` Eric Biggers
@ 2019-01-14  9:26           ` Stephan Müller
  0 siblings, 0 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-14  9:26 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Am Samstag, 12. Januar 2019, 06:26:46 CET schrieb Eric Biggers:

Hi Eric,


[...]

Thanks. I integrated updates for all comments.

Ciao
Stephan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function
  2019-01-12  5:12         ` Eric Biggers
  2019-01-12  9:55           ` Herbert Xu
@ 2019-01-14  9:30           ` Stephan Müller
  2019-01-14 17:53             ` Eric Biggers
  1 sibling, 1 reply; 36+ messages in thread
From: Stephan Müller @ 2019-01-14  9:30 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Am Samstag, 12. Januar 2019, 06:12:54 CET schrieb Eric Biggers:

Hi Eric,

[...]

> > The extract and expand phases use different instances of the underlying
> > keyed message digest cipher to ensure that while the extraction phase
> > generates a new key for the expansion phase, the cipher for the
> > expansion phase can still be used. This approach is intended to aid
> > multi-threaded uses cases.
> 
> I think you partially misunderstood what I was asking for.  One HMAC tfm is
> sufficient as long as HKDF-Expand is separated from HKDF-Extract, which
> you've done.  So just use one HMAC tfm, and in crypto_hkdf_seed() key it
> with the 'salt', and then afterwards with the 'prk'.

Ok, thanks for the clarification. I will remove the 2nd HMAC TFM then.
> 
> Also everywhere in this patchset, please avoid using the word "cipher" to
> refer to algorithms that are not encryption/decryption.  I know a lot of
> the crypto API docs do this, but I think it is a mistake and confusing. 
> Hash algorithms and KDFs are not "ciphers".

As you wish, I will refer to specific name of the cryptographic operation.

[...]

> > + * NOTE: In-place cipher operations are not supported.
> > + */
> 
> What does an "in-place cipher operation" mean in this context?  That the
> 'info' buffer must not overlap the 'dst' buffer? 

Correct, no overlapping.

> Maybe
> crypto_rng_generate() should check that for all crypto_rngs?  Or is it
> different for different crypto_rngs?

This is the case in general for all KDFs (and even RNGs). It is no technical 
or cryptographic error to have overlapping buffers. The only issue is that the 
result will not match the expected value.

The issue is that the input buffer to the generate function is an input to 
every round of the KDF. If the input and output buffer overlap, starting with 
the 2nd iteration of the KDF, the input is the output of the 1st round. Again, 
I do not think it is a cryptographic error though.

(To support my conclusion: A colleague of mine has proposed an update to the 
HKDF specification where the input data changes for each KDF round. This 
proposal was considered appropriate by one of the authors of HKDF.)

If the requested output is smaller or equal to the output block size of the 
KDF, overlapping buffers are even harmless since the implementation will 
calculate the correct output.

Due to that, I removed the statement. But I am not sure we should add a 
technical block to deny overlapping input/output buffers.

[...]
> > 
> > +	desc->flags = crypto_shash_get_flags(expand_kmd) &
> > +		      CRYPTO_TFM_REQ_MAY_SLEEP;
> 
> This line setting desc->flags doesn't make sense.  How is the user meant to
> control whether crypto_rng_generate() can sleep or not?  Or can it always
> sleep? Either way this part is wrong since the user can't get access to the
> HMAC tfm to set this flag being checked for.

Could you please help me why a user should set this flag? Isn't the 
implementation specifying that flag to allow identifying whether the 
implementation could or could not sleep? Thus, we simply copy the sleeping 
flag from the lower level keyed message digest implementation.

At least that is also the implementation found in crypto/hmac.c.

[...]

> > +		if (dlen < h) {
> > +			u8 tmpbuffer[CRYPTO_HKDF_MAX_DIGESTSIZE];
> > +
> > +			err = crypto_shash_finup(desc, &ctr, 1, tmpbuffer);
> > +			if (err)
> > +				goto out;
> > +			memcpy(dst, tmpbuffer, dlen);
> > +			memzero_explicit(tmpbuffer, h);
> > +			goto out;
> > +		} else {
> 
> No need for the 'else'.

Could you please help me why that else branch is not needed? If the buffer to 
be generated is equal or larger than the output block length of the keyed 
message digest, I would like to directly operate on the output buffer to avoid 
a memcpy.
> 
> > +			err = crypto_shash_finup(desc, &ctr, 1, dst);
> > +			if (err)
> > +				goto out;
> > +
> > +			prev = dst;
> > +			dst += h;
> > +			dlen -= h;
> > +			ctr++;
> > +		}
> > +	}

[...]
> 
> > +	struct crypto_shash *extract_kmd = ctx->extract_kmd;
> > +	struct crypto_shash *expand_kmd = ctx->expand_kmd;
> > +	struct rtattr *rta = (struct rtattr *)seed;
> > +	SHASH_DESC_ON_STACK(desc, extract_kmd);
> > +	u32 saltlen;
> > +	unsigned int h = crypto_shash_digestsize(extract_kmd);
> > +	int err;
> > +	const uint8_t null_salt[CRYPTO_HKDF_MAX_DIGESTSIZE] = { 0 };
> 
> static const
> 

Why would I want to turn that buffer into a static variable? All we need it 
for is in case there is no salt provided.

[...]

> > +
> > +	if (!RTA_OK(rta, slen))
> > +		return -EINVAL;
> > +	if (rta->rta_type != 1)
> > +		return -EINVAL;
> > +	if (RTA_PAYLOAD(rta) < sizeof(saltlen))
> > +		return -EINVAL;
> > +	saltlen = *((u32 *)RTA_DATA(rta));
> 
> I'm guessing you copied the weird "length as a rtattr payload" approach from
> the authenc template.  I think it's not necessary.  And it's overly
> error-prone, as shown by the authenc template getting the parsing wrong for
> years and you making the exact same mistake again here...
> (See https://patchwork.kernel.org/patch/10732803/)  How about just using a
> u32 at the beginning without the 'rtattr' preceding it?

I was not sure whether this approach would be acceptable. I very much would 
love to have a u32 pre-pended only without the RTA business.

I updated the implementation accordingly.
> 
[...]

> 
> > +	alg = &salg->base;
> 
> Check here that the underlying algorithm really is "hmac(" something?

I added a check for the presence of salg->setkey.
> 
> Alternatively it may be a good idea to simplify usage by making the template
> just take the unkeyed hash directly, like "hkdf(sha512)".  And if any users
> really need to specify a specific HMAC implementation then another template
> usable as "hkdf_base(hmac(sha512))" could be added later.
> 

I would not suggest this, because that rounds contrary to the concept of the 
kernel crypto API IMHO. The caller has to provide the wrapping cipher. It is 
perfectly viable to allow a caller to invoke a specific keyed message digest.

[...]

Thank you very much for your code review.

Ciao
Stephan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 2/6] crypto: kdf - SP800-108 Key Derivation Function
  2019-01-12  5:27         ` Eric Biggers
@ 2019-01-14  9:31           ` Stephan Müller
  0 siblings, 0 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-14  9:31 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Am Samstag, 12. Januar 2019, 06:27:59 CET schrieb Eric Biggers:

Hi Eric,

[...]
> > 
> > +obj-$(CONFIG_CRYPTO_KDF) += kdf.o
> 
> This naming is too generic.  CONFIG_CRYPTO_KDF and kdf.c imply that this is
> related to all KDFs.  But actually it is an implementation of a few specific
> KDFs.  Can you give it a clearer name, like KDF_SP800?
> 
I am going to use kdf_sp800108 or CRYPTO_CONFIG_KDF_SP800108. The reason is 
that there are many SP800 documents.

Thanks

Ciao
Stephan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 5/6] crypto: hkdf - add known answer tests
  2019-01-14  9:25           ` Stephan Müller
@ 2019-01-14 17:44             ` Eric Biggers
  0 siblings, 0 replies; 36+ messages in thread
From: Eric Biggers @ 2019-01-14 17:44 UTC (permalink / raw)
  To: Stephan Müller
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

On Mon, Jan 14, 2019 at 10:25:16AM +0100, Stephan Müller wrote:
> Am Samstag, 12. Januar 2019, 06:19:15 CET schrieb Eric Biggers:
> 
> Hi Eric,
> 
> [...]
> > 
> > > +			}
> > > +		}
> > > +	}, {
> > > +		.alg = "hkdf(hmac(sha224))",
> > > +		.test = alg_test_null,
> > > +		.fips_allowed = 1,
> > 
> > I think it is dumb to add algorithms to the testmgr with no tests just so
> > the 'fips_allowed' flag can be set. 
> 
> Currently it is the only way. But I agree that it could be done better.
> 
> > And doesn't FIPS sometimes require
> > tests anyway?  I don't think the "null test" should count as a test :-)
> 
> Yes, it DOES count as a test (as strange as it may sound)! :-)
> 
> The FIPS requirements are as follows:
> 
> - raw ciphers must be subject to a FIPS test with one block chaining mode to 
> cover that cipher with all block chaining modes (e.g. you can test ecb(aes) to 
> cover AES with *all* existing block chaining modes).
> 
> - for compound crypto algorithm (like RSA with respect to hashes, KDF with 
> respect to the keyed message digest, HMAC with respect to hashes), the 
> wrapping crypto algorithm needs to be tested with *one* wrapped cipher at 
> least (but also not more. E.g. if you have a self test for, say, all SHA-1 and 
> SHA-2, you only need one HMAC SHA test or one KDF HMAC SHA test.
> 
> - in some circumstances, it is even permissible to test wrapping crypto 
> algorithms where the underlying algo is implicitly tested. E.g. if you have a 
> HMAC SHA-256 test, you do not need an individual SHA-256 test.
> 
> 
> > 
> > Perhaps just include sha256 and sha512, and have tests for them?
> 
> Do you happen to have an official SHA-512 HKDF test vector? RFC5869 only has 
> SHA-1 and SHA-256 tests.
> > 
> 

No, I don't know of any official HKDF-SHA512 test vectors.

> [...]
> > > 
> > > +/* Test vectors from RFC 5869 appendix A */
> > > +static struct kdf_testvec hkdf_hmac_sha256_tv_template[] = {
> > 
> > const
> > 
> > Likewise for all other kdf_testvecs.
> 
> const does not work with __VECS :-(
> 
> I leave it without const at the moment. I think the __VECS should be updated 
> along with all test vectors.
> 
> [...]

I don't see why.  kdf_testvec just needs to be made const everywhere.

- Eric

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function
  2019-01-14  9:30           ` Stephan Müller
@ 2019-01-14 17:53             ` Eric Biggers
  2019-01-14 18:44               ` Stephan Mueller
  0 siblings, 1 reply; 36+ messages in thread
From: Eric Biggers @ 2019-01-14 17:53 UTC (permalink / raw)
  To: Stephan Müller
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

On Mon, Jan 14, 2019 at 10:30:39AM +0100, Stephan Müller wrote:
> Am Samstag, 12. Januar 2019, 06:12:54 CET schrieb Eric Biggers:
> 
> Hi Eric,
> 
> [...]
> 
> > > The extract and expand phases use different instances of the underlying
> > > keyed message digest cipher to ensure that while the extraction phase
> > > generates a new key for the expansion phase, the cipher for the
> > > expansion phase can still be used. This approach is intended to aid
> > > multi-threaded uses cases.
> > 
> > I think you partially misunderstood what I was asking for.  One HMAC tfm is
> > sufficient as long as HKDF-Expand is separated from HKDF-Extract, which
> > you've done.  So just use one HMAC tfm, and in crypto_hkdf_seed() key it
> > with the 'salt', and then afterwards with the 'prk'.
> 
> Ok, thanks for the clarification. I will remove the 2nd HMAC TFM then.
> > 
> > Also everywhere in this patchset, please avoid using the word "cipher" to
> > refer to algorithms that are not encryption/decryption.  I know a lot of
> > the crypto API docs do this, but I think it is a mistake and confusing. 
> > Hash algorithms and KDFs are not "ciphers".
> 
> As you wish, I will refer to specific name of the cryptographic operation.
> 
> [...]
> 
> > > + * NOTE: In-place cipher operations are not supported.
> > > + */
> > 
> > What does an "in-place cipher operation" mean in this context?  That the
> > 'info' buffer must not overlap the 'dst' buffer? 
> 
> Correct, no overlapping.
> 
> > Maybe
> > crypto_rng_generate() should check that for all crypto_rngs?  Or is it
> > different for different crypto_rngs?
> 
> This is the case in general for all KDFs (and even RNGs). It is no technical 
> or cryptographic error to have overlapping buffers. The only issue is that the 
> result will not match the expected value.
> 
> The issue is that the input buffer to the generate function is an input to 
> every round of the KDF. If the input and output buffer overlap, starting with 
> the 2nd iteration of the KDF, the input is the output of the 1st round. Again, 
> I do not think it is a cryptographic error though.
> 
> (To support my conclusion: A colleague of mine has proposed an update to the 
> HKDF specification where the input data changes for each KDF round. This 
> proposal was considered appropriate by one of the authors of HKDF.)
> 
> If the requested output is smaller or equal to the output block size of the 
> KDF, overlapping buffers are even harmless since the implementation will 
> calculate the correct output.
> 
> Due to that, I removed the statement. But I am not sure we should add a 
> technical block to deny overlapping input/output buffers.
> 
> [...]
> > > 
> > > +	desc->flags = crypto_shash_get_flags(expand_kmd) &
> > > +		      CRYPTO_TFM_REQ_MAY_SLEEP;
> > 
> > This line setting desc->flags doesn't make sense.  How is the user meant to
> > control whether crypto_rng_generate() can sleep or not?  Or can it always
> > sleep? Either way this part is wrong since the user can't get access to the
> > HMAC tfm to set this flag being checked for.
> 
> Could you please help me why a user should set this flag? Isn't the 
> implementation specifying that flag to allow identifying whether the 
> implementation could or could not sleep? Thus, we simply copy the sleeping 
> flag from the lower level keyed message digest implementation.
> 
> At least that is also the implementation found in crypto/hmac.c.
> 
> [...]

Whether the crypto_shash* stuff can sleep is controlled on a per-request basis,
not a per-implementation basis.  So I don't understand what you are talking
about here.

> 
> > > +		if (dlen < h) {
> > > +			u8 tmpbuffer[CRYPTO_HKDF_MAX_DIGESTSIZE];
> > > +
> > > +			err = crypto_shash_finup(desc, &ctr, 1, tmpbuffer);
> > > +			if (err)
> > > +				goto out;
> > > +			memcpy(dst, tmpbuffer, dlen);
> > > +			memzero_explicit(tmpbuffer, h);
> > > +			goto out;
> > > +		} else {
> > 
> > No need for the 'else'.
> 
> Could you please help me why that else branch is not needed? If the buffer to 
> be generated is equal or larger than the output block length of the keyed 
> message digest, I would like to directly operate on the output buffer to avoid 
> a memcpy.

I'm simply saying you don't need the 'else' keyword as the previous block ends
with a goto.

> > 
> > > +			err = crypto_shash_finup(desc, &ctr, 1, dst);
> > > +			if (err)
> > > +				goto out;
> > > +
> > > +			prev = dst;
> > > +			dst += h;
> > > +			dlen -= h;
> > > +			ctr++;
> > > +		}
> > > +	}
> 
> [...]
> > 
> > > +	struct crypto_shash *extract_kmd = ctx->extract_kmd;
> > > +	struct crypto_shash *expand_kmd = ctx->expand_kmd;
> > > +	struct rtattr *rta = (struct rtattr *)seed;
> > > +	SHASH_DESC_ON_STACK(desc, extract_kmd);
> > > +	u32 saltlen;
> > > +	unsigned int h = crypto_shash_digestsize(extract_kmd);
> > > +	int err;
> > > +	const uint8_t null_salt[CRYPTO_HKDF_MAX_DIGESTSIZE] = { 0 };
> > 
> > static const
> > 
> 
> Why would I want to turn that buffer into a static variable? All we need it 
> for is in case there is no salt provided.
> 
> [...]
> 
> > > +
> > > +	if (!RTA_OK(rta, slen))
> > > +		return -EINVAL;
> > > +	if (rta->rta_type != 1)
> > > +		return -EINVAL;
> > > +	if (RTA_PAYLOAD(rta) < sizeof(saltlen))
> > > +		return -EINVAL;
> > > +	saltlen = *((u32 *)RTA_DATA(rta));
> > 
> > I'm guessing you copied the weird "length as a rtattr payload" approach from
> > the authenc template.  I think it's not necessary.  And it's overly
> > error-prone, as shown by the authenc template getting the parsing wrong for
> > years and you making the exact same mistake again here...
> > (See https://patchwork.kernel.org/patch/10732803/)  How about just using a
> > u32 at the beginning without the 'rtattr' preceding it?
> 
> I was not sure whether this approach would be acceptable. I very much would 
> love to have a u32 pre-pended only without the RTA business.
> 
> I updated the implementation accordingly.
> > 
> [...]
> 
> > 
> > > +	alg = &salg->base;
> > 
> > Check here that the underlying algorithm really is "hmac(" something?
> 
> I added a check for the presence of salg->setkey.
> > 
> > Alternatively it may be a good idea to simplify usage by making the template
> > just take the unkeyed hash directly, like "hkdf(sha512)".  And if any users
> > really need to specify a specific HMAC implementation then another template
> > usable as "hkdf_base(hmac(sha512))" could be added later.
> > 
> 
> I would not suggest this, because that rounds contrary to the concept of the 
> kernel crypto API IMHO. The caller has to provide the wrapping cipher. It is 
> perfectly viable to allow a caller to invoke a specific keyed message digest.
> 

Sure, but it would not conform to the HKDF specification.  Are you sure it is
okay to specify an arbitrary keyed hash?

> [...]
> 
> Thank you very much for your code review.
> 
> Ciao
> Stephan
> 
> 

- Eric

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function
  2019-01-14 17:53             ` Eric Biggers
@ 2019-01-14 18:44               ` Stephan Mueller
  0 siblings, 0 replies; 36+ messages in thread
From: Stephan Mueller @ 2019-01-14 18:44 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Herbert Xu, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Am Montag, 14. Januar 2019, 18:53:16 CET schrieb Eric Biggers:

Hi Eric,

> > I would not suggest this, because that rounds contrary to the concept of
> > the kernel crypto API IMHO. The caller has to provide the wrapping
> > cipher. It is perfectly viable to allow a caller to invoke a specific
> > keyed message digest.
> Sure, but it would not conform to the HKDF specification.  Are you sure it
> is okay to specify an arbitrary keyed hash?

Technically, I see no issue why this should not be possible. You see that with 
the SP800-108 KDF implementations where using CMAC is perfectly legal (and 
which I also test).

Though, using another keyed hash implementation like CMAC is not covered by 
the HKDF spec. If a caller would use hkdf(cmac(aes)), it would produce 
cryptographically strong values. Though this implementation does not conform 
to any standard. I do not think we should prevent a caller to select such 
combination in the kernel crypto API.

IMHO there would even be valid reasons why one would use cmac(aes) for a kdf. 
For example, when you would want to use a hardware AES which somehow also 
employs a hardware key that is inaccessible to software in order to tie the 
KDF result to the local hardware. This could even be a valid use case for Ext4 
FBE encryption where you derive a key. The KDF could be used to link the 
derived key to the local hardware to prevent the encrypted data could be 
copied to another system and decrypted successfully there.

Ciao
Stephan

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v2 0/6] General Key Derivation Function Support
  2019-01-11 19:08     ` [PATCH 0/6] General Key Derivation Function Support Stephan Müller
                         ` (5 preceding siblings ...)
  2019-01-11 19:11       ` [PATCH 6/6] crypto: tcrypt - add KDF test invocation Stephan Müller
@ 2019-01-16 11:06       ` Stephan Müller
  2019-01-16 11:07         ` [PATCH v2 1/6] crypto: add template handling for RNGs Stephan Müller
                           ` (6 more replies)
  6 siblings, 7 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-16 11:06 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Changes v2:
* Incorporation of all comments from Eric Biggers

Stephan Mueller (6):
  crypto: add template handling for RNGs
  crypto: kdf - SP800-108 Key Derivation Function
  crypto: kdf - add known answer tests
  crypto: hkdf - HMAC-based Extract-and-Expand KDF
  crypto: hkdf - add known answer tests
  crypto: tcrypt - add KDF test invocation

 crypto/Kconfig                |  13 +
 crypto/Makefile               |   2 +
 crypto/hkdf.c                 | 272 +++++++++++++++++++
 crypto/kdf_sp800108.c         | 491 ++++++++++++++++++++++++++++++++++
 crypto/rng.c                  |  44 +++
 crypto/tcrypt.c               |   8 +
 crypto/testmgr.c              | 245 +++++++++++++++++
 crypto/testmgr.h              | 198 ++++++++++++++
 include/crypto/internal/rng.h |  26 ++
 9 files changed, 1299 insertions(+)
 create mode 100644 crypto/hkdf.c
 create mode 100644 crypto/kdf_sp800108.c

-- 
2.20.1

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH v2 1/6] crypto: add template handling for RNGs
  2019-01-16 11:06       ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Müller
@ 2019-01-16 11:07         ` Stephan Müller
  2019-01-16 11:08         ` [PATCH v2 2/6] crypto: kdf - SP800-108 Key Derivation Function Stephan Müller
                           ` (5 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-16 11:07 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Adds ability to register templates for pseudo random number generators
(PRNG). PRNGs are "meta" mechanisms using raw cipher primitives. Thus,
PRNGs can now be implemented as templates to allow the complete
flexibility the kernel crypto API provides.

The RNG API provides access to the PRNG algorithms without an entropy
management.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/rng.c                  | 44 +++++++++++++++++++++++++++++++++++
 include/crypto/internal/rng.h | 26 +++++++++++++++++++++
 2 files changed, 70 insertions(+)

diff --git a/crypto/rng.c b/crypto/rng.c
index 33c38a72bff5..da4fd03c0acd 100644
--- a/crypto/rng.c
+++ b/crypto/rng.c
@@ -64,6 +64,25 @@ static int crypto_rng_init_tfm(struct crypto_tfm *tfm)
 	return 0;
 }
 
+static inline struct rng_alg *__crypto_rng_alg(struct crypto_alg *alg)
+{
+	return container_of(alg, struct rng_alg, base);
+}
+
+static inline struct rng_instance *rng_instance(
+	struct crypto_instance *inst)
+{
+	return container_of(__crypto_rng_alg(&inst->alg),
+			    struct rng_instance, alg);
+}
+
+static void crypto_rng_free_instance(struct crypto_instance *inst)
+{
+	struct rng_instance *rng = rng_instance(inst);
+
+	rng->free(rng);
+}
+
 static unsigned int seedsize(struct crypto_alg *alg)
 {
 	struct rng_alg *ralg = container_of(alg, struct rng_alg, base);
@@ -102,6 +121,7 @@ static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg)
 static const struct crypto_type crypto_rng_type = {
 	.extsize = crypto_alg_extsize,
 	.init_tfm = crypto_rng_init_tfm,
+	.free = crypto_rng_free_instance,
 #ifdef CONFIG_PROC_FS
 	.show = crypto_rng_show,
 #endif
@@ -229,5 +249,29 @@ void crypto_unregister_rngs(struct rng_alg *algs, int count)
 }
 EXPORT_SYMBOL_GPL(crypto_unregister_rngs);
 
+static int rng_prepare_alg(struct rng_alg *alg)
+{
+	struct crypto_alg *base = &alg->base;
+
+	base->cra_type = &crypto_rng_type;
+	base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+	base->cra_flags |= CRYPTO_ALG_TYPE_RNG;
+
+	return 0;
+}
+
+int rng_register_instance(struct crypto_template *tmpl,
+			  struct rng_instance *inst)
+{
+	int err;
+
+	err = rng_prepare_alg(&inst->alg);
+	if (err)
+		return err;
+
+	return crypto_register_instance(tmpl, rng_crypto_instance(inst));
+}
+EXPORT_SYMBOL_GPL(rng_register_instance);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Random Number Generator");
diff --git a/include/crypto/internal/rng.h b/include/crypto/internal/rng.h
index a52ef3483dd7..bfe4482ad336 100644
--- a/include/crypto/internal/rng.h
+++ b/include/crypto/internal/rng.h
@@ -42,4 +42,30 @@ static inline void crypto_rng_set_entropy(struct crypto_rng *tfm,
 	crypto_rng_alg(tfm)->set_ent(tfm, data, len);
 }
 
+struct rng_instance {
+	void (*free)(struct rng_instance *inst);
+	struct rng_alg alg;
+};
+
+static inline struct rng_instance *rng_alloc_instance(
+	const char *name, struct crypto_alg *alg)
+{
+	return crypto_alloc_instance(name, alg,
+			      sizeof(struct rng_instance) - sizeof(*alg));
+}
+
+static inline struct crypto_instance *rng_crypto_instance(
+	struct rng_instance *inst)
+{
+	return container_of(&inst->alg.base, struct crypto_instance, alg);
+}
+
+static inline void *rng_instance_ctx(struct rng_instance *inst)
+{
+	return crypto_instance_ctx(rng_crypto_instance(inst));
+}
+
+int rng_register_instance(struct crypto_template *tmpl,
+			  struct rng_instance *inst);
+
 #endif
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 2/6] crypto: kdf - SP800-108 Key Derivation Function
  2019-01-16 11:06       ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Müller
  2019-01-16 11:07         ` [PATCH v2 1/6] crypto: add template handling for RNGs Stephan Müller
@ 2019-01-16 11:08         ` Stephan Müller
  2019-01-16 11:08         ` [PATCH v2 3/6] crypto: kdf - add known answer tests Stephan Müller
                           ` (4 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-16 11:08 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

The SP800-108 compliant Key Derivation Function provides three KDF
types which are all implemented, including the counter-based KDF,
the double-pipeline KDF and the feedback KDF.

The code comments provide details about how to invoke the different KDF
types.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/Kconfig        |   7 +
 crypto/Makefile       |   1 +
 crypto/kdf_sp800108.c | 491 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 499 insertions(+)
 create mode 100644 crypto/kdf_sp800108.c

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 86960aa53e0f..7c0336c9ba9c 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -561,6 +561,13 @@ config CRYPTO_HMAC
 	  HMAC: Keyed-Hashing for Message Authentication (RFC2104).
 	  This is required for IPSec.
 
+config CRYPTO_KDF_SP800108
+	tristate "Key Derivation Function (SP800-108)"
+	select CRYPTO_RNG
+	help
+	  Support for KDF compliant to SP800-108. All three types of
+	  KDF specified in SP800-108 are implemented.
+
 config CRYPTO_XCBC
 	tristate "XCBC support"
 	select CRYPTO_HASH
diff --git a/crypto/Makefile b/crypto/Makefile
index 799ed5e94606..eead7ec9fd8e 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -58,6 +58,7 @@ crypto_user-y := crypto_user_base.o
 crypto_user-$(CONFIG_CRYPTO_STATS) += crypto_user_stat.o
 obj-$(CONFIG_CRYPTO_CMAC) += cmac.o
 obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
+obj-$(CONFIG_CRYPTO_KDF_SP800108) += kdf_sp800108.o
 obj-$(CONFIG_CRYPTO_VMAC) += vmac.o
 obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
 obj-$(CONFIG_CRYPTO_NULL2) += crypto_null.o
diff --git a/crypto/kdf_sp800108.c b/crypto/kdf_sp800108.c
new file mode 100644
index 000000000000..33b26659afa7
--- /dev/null
+++ b/crypto/kdf_sp800108.c
@@ -0,0 +1,491 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * SP800-108 Key-derivation function
+ *
+ * Copyright (C) 2019, Stephan Mueller <smueller@chronox.de>
+ */
+
+/*
+ * For performing a KDF operation, the following input is required
+ * from the caller:
+ *
+ *	* Keying material to be used to derive the new keys from
+ *	  (denoted as Ko in SP800-108)
+ *	* Label -- a free form binary string
+ *	* Context -- a free form binary string
+ *
+ * The KDF is implemented as a random number generator.
+ *
+ * The Ko keying material is to be provided with the initialization of the KDF
+ * "random number generator", i.e. with the crypto_rng_reset function.
+ *
+ * The Label and Context concatenated string is provided when obtaining random
+ * numbers, i.e. with the crypto_rng_generate function. The caller must format
+ * the free-form Label || Context input as deemed necessary for the given
+ * purpose. Note, SP800-108 mandates that the Label and Context are separated
+ * by a 0x00 byte, i.e. the caller shall provide the input as
+ * Label || 0x00 || Context when trying to be compliant to SP800-108. For
+ * the feedback KDF, an IV is required as documented below.
+ *
+ * Example without proper error handling:
+ *	char *keying_material = "\x00\x11\x22\x33\x44\x55\x66\x77";
+ *	char *label_context = "\xde\xad\xbe\xef\x00\xde\xad\xbe\xef";
+ *	kdf = crypto_alloc_rng(name, 0, 0);
+ *	crypto_rng_reset(kdf, keying_material, 8);
+ *	crypto_rng_generate(kdf, label_context, 9, outbuf, outbuflen);
+ */
+
+#include <linux/module.h>
+#include <crypto/rng.h>
+#include <crypto/internal/rng.h>
+#include <crypto/hash.h>
+#include <crypto/internal/hash.h>
+
+struct crypto_kdf_ctx {
+	struct crypto_shash *kmd;
+};
+
+#define CRYPTO_KDF_MAX_DIGESTSIZE	64
+#define CRYPTO_KDF_MAX_ALIGNMASK	0x3f
+
+static inline void crypto_kdf_init_desc(struct shash_desc *desc,
+					struct crypto_shash *kmd)
+{
+	desc->tfm = kmd;
+	desc->flags = 0;
+}
+
+/*
+ * Implementation of the KDF in double pipeline iteration mode according with
+ * counter to SP800-108 section 5.3.
+ *
+ * The caller must provide Label || 0x00 || Context in src. This src pointer
+ * may also be NULL if the caller wishes not to provide anything.
+ */
+static int crypto_kdf_dpi_generate(struct crypto_rng *rng,
+				   const u8 *src, unsigned int slen,
+				   u8 *dst, unsigned int dlen)
+{
+	const struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	struct crypto_shash *kmd = ctx->kmd;
+	SHASH_DESC_ON_STACK(desc, kmd);
+	__be32 counter = cpu_to_be32(1);
+	const unsigned int h = crypto_shash_digestsize(kmd);
+	const unsigned int alignmask = crypto_shash_alignmask(kmd);
+	int err = 0;
+	u8 *dst_orig = dst;
+	u8 Aiblock[CRYPTO_KDF_MAX_DIGESTSIZE + CRYPTO_KDF_MAX_ALIGNMASK];
+	u8 *Ai = PTR_ALIGN((u8 *)Aiblock, alignmask + 1);
+
+	crypto_kdf_init_desc(desc, kmd);
+
+	memset(Ai, 0, h);
+
+	while (dlen) {
+		/* Calculate A(i) */
+		if (dst == dst_orig && src && slen)
+			/* 5.3 step 4 and 5.a */
+			err = crypto_shash_digest(desc, src, slen, Ai);
+		else
+			/* 5.3 step 5.a */
+			err = crypto_shash_digest(desc, Ai, h, Ai);
+		if (err)
+			goto out;
+
+		/* Calculate K(i) -- step 5.b */
+		err = crypto_shash_init(desc);
+		if (err)
+			goto out;
+
+		err = crypto_shash_update(desc, Ai, h);
+		if (err)
+			goto out;
+
+		err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32));
+		if (err)
+			goto out;
+		if (src && slen) {
+			err = crypto_shash_update(desc, src, slen);
+			if (err)
+				goto out;
+		}
+
+		if (dlen < h) {
+			u8 tmpbuffer[CRYPTO_KDF_MAX_DIGESTSIZE];
+
+			err = crypto_shash_final(desc, tmpbuffer);
+			if (err)
+				goto out;
+			memcpy(dst, tmpbuffer, dlen);
+			memzero_explicit(tmpbuffer, h);
+			goto out;
+		}
+
+		err = crypto_shash_final(desc, dst);
+		if (err)
+			goto out;
+		dlen -= h;
+		dst += h;
+		counter = cpu_to_be32(be32_to_cpu(counter) + 1);
+	}
+
+out:
+	if (err)
+		memzero_explicit(dst_orig, dlen);
+	shash_desc_zero(desc);
+	memzero_explicit(Ai, h);
+	return err;
+}
+
+/*
+ * Implementation of the KDF in feedback mode with a non-NULL IV and with
+ * counter according to SP800-108 section 5.2. The IV is supplied with src
+ * and must be equal to the digestsize of the used keyed message digest.
+ *
+ * In addition, the caller must provide Label || 0x00 || Context in src. This
+ * src pointer must not be NULL as the IV is required. The ultimate format of
+ * the src pointer is IV || Label || 0x00 || Context where the length of the
+ * IV is equal to the output size of the PRF.
+ */
+static int crypto_kdf_fb_generate(struct crypto_rng *rng,
+				  const u8 *src, unsigned int slen,
+				  u8 *dst, unsigned int dlen)
+{
+	const struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	struct crypto_shash *kmd = ctx->kmd;
+	SHASH_DESC_ON_STACK(desc, kmd);
+	__be32 counter = cpu_to_be32(1);
+	const unsigned int h = crypto_shash_digestsize(kmd);
+	unsigned int labellen = 0;
+	int err = 0;
+	u8 *dst_orig = dst;
+	const u8 *label;
+
+	/* require the presence of an IV */
+	if (!src || slen < h)
+		return -EINVAL;
+
+	crypto_kdf_init_desc(desc, kmd);
+
+	/* calculate the offset of the label / context data */
+	label = src + h;
+	labellen = slen - h;
+
+	while (dlen) {
+		err = crypto_shash_init(desc);
+		if (err)
+			goto out;
+
+		/*
+		 * Feedback mode applies to all rounds except first which uses
+		 * the IV.
+		 */
+		if (dst_orig == dst)
+			err = crypto_shash_update(desc, src, h);
+		else
+			err = crypto_shash_update(desc, dst - h, h);
+		if (err)
+			goto out;
+
+		err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32));
+		if (err)
+			goto out;
+		if (labellen) {
+			err = crypto_shash_update(desc, label, labellen);
+			if (err)
+				goto out;
+		}
+
+		if (dlen < h) {
+			u8 tmpbuffer[CRYPTO_KDF_MAX_DIGESTSIZE];
+
+			err = crypto_shash_final(desc, tmpbuffer);
+			if (err)
+				goto out;
+			memcpy(dst, tmpbuffer, dlen);
+			memzero_explicit(tmpbuffer, h);
+			goto out;
+		}
+
+		err = crypto_shash_final(desc, dst);
+		if (err)
+			goto out;
+		dlen -= h;
+		dst += h;
+		counter = cpu_to_be32(be32_to_cpu(counter) + 1);
+	}
+
+out:
+	if (err)
+		memzero_explicit(dst_orig, dlen);
+	return err;
+}
+
+/*
+ * Implementation of the KDF in counter mode according to SP800-108 section 5.1
+ * as well as SP800-56A section 5.8.1 (Single-step KDF).
+ *
+ * SP800-108:
+ * The caller must provide Label || 0x00 || Context in src. This src pointer
+ * may also be NULL if the caller wishes not to provide anything.
+ *
+ * SP800-56A:
+ * The key provided for the HMAC during the crypto_rng_reset shall NOT be the
+ * shared secret from the DH operation, but an independently generated key.
+ * The src pointer is defined as Z || other info where Z is the shared secret
+ * from DH and other info is an arbitrary string (see SP800-56A section
+ * 5.8.1.2).
+ */
+static int crypto_kdf_ctr_generate(struct crypto_rng *rng,
+				   const u8 *src, unsigned int slen,
+				   u8 *dst, unsigned int dlen)
+{
+	const struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	struct crypto_shash *kmd = ctx->kmd;
+	SHASH_DESC_ON_STACK(desc, kmd);
+	__be32 counter = cpu_to_be32(1);
+	const unsigned int h = crypto_shash_digestsize(kmd);
+	int err = 0;
+	u8 *dst_orig = dst;
+
+	crypto_kdf_init_desc(desc, kmd);
+
+	while (dlen) {
+		err = crypto_shash_init(desc);
+		if (err)
+			goto out;
+
+		err = crypto_shash_update(desc, (u8 *)&counter, sizeof(__be32));
+		if (err)
+			goto out;
+
+		if (src && slen) {
+			err = crypto_shash_update(desc, src, slen);
+			if (err)
+				goto out;
+		}
+
+		if (dlen < h) {
+			u8 tmpbuffer[CRYPTO_KDF_MAX_DIGESTSIZE];
+
+			err = crypto_shash_final(desc, tmpbuffer);
+			if (err)
+				goto out;
+			memcpy(dst, tmpbuffer, dlen);
+			memzero_explicit(tmpbuffer, h);
+			return 0;
+		}
+
+		err = crypto_shash_final(desc, dst);
+		if (err)
+			goto out;
+
+		dlen -= h;
+		dst += h;
+		counter = cpu_to_be32(be32_to_cpu(counter) + 1);
+	}
+
+out:
+	if (err)
+		memzero_explicit(dst_orig, dlen);
+	shash_desc_zero(desc);
+	return err;
+}
+
+/*
+ * The seeding of the KDF allows to set a key which must be at least
+ * digestsize long.
+ */
+static int crypto_kdf_seed(struct crypto_rng *rng,
+			   const u8 *seed, unsigned int slen)
+{
+	const struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	unsigned int ds = crypto_shash_digestsize(ctx->kmd);
+
+	/* Check according to SP800-108 section 7.2 */
+	if (ds > slen)
+		return -EINVAL;
+
+	/*
+	 * We require that we operate on a MAC -- if we do not operate on a
+	 * MAC, this function returns an error.
+	 */
+	return crypto_shash_setkey(ctx->kmd, seed, slen);
+}
+
+static int crypto_kdf_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+	struct crypto_shash_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_shash *kmd;
+
+	kmd = crypto_spawn_shash(spawn);
+	if (IS_ERR(kmd))
+		return PTR_ERR(kmd);
+
+	ctx->kmd = kmd;
+
+	return 0;
+}
+
+static void crypto_kdf_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_kdf_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_shash(ctx->kmd);
+}
+
+static void crypto_kdf_free(struct rng_instance *inst)
+{
+	crypto_drop_spawn(rng_instance_ctx(inst));
+	kfree(inst);
+}
+
+static int crypto_kdf_alloc_common(struct crypto_template *tmpl,
+				   struct rtattr **tb,
+				   const u8 *name,
+				   int (*generate)(struct crypto_rng *tfm,
+						   const u8 *src,
+						   unsigned int slen,
+						   u8 *dst, unsigned int dlen))
+{
+	struct rng_instance *inst;
+	struct crypto_alg *alg;
+	struct shash_alg *salg;
+	int err;
+	unsigned int ds;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_RNG);
+	if (err)
+		return err;
+
+	salg = shash_attr_alg(tb[1], 0, 0);
+	if (IS_ERR(salg))
+		return PTR_ERR(salg);
+
+	/* Require a keyed message digest */
+	if (!salg->setkey)
+		return -EOPNOTSUPP;
+
+	ds = salg->digestsize;
+	/* Hashes with no digest size are not allowed for KDFs. */
+	if (!ds || WARN_ON(ds > CRYPTO_KDF_MAX_DIGESTSIZE))
+		return -EOPNOTSUPP;
+
+	alg = &salg->base;
+	if (WARN_ON(CRYPTO_KDF_MAX_ALIGNMASK < alg->cra_alignmask))
+		return -EOPNOTSUPP;
+
+	inst = rng_alloc_instance(name, alg);
+	err = PTR_ERR(inst);
+	if (IS_ERR(inst))
+		goto out_put_alg;
+
+	err = crypto_init_shash_spawn(rng_instance_ctx(inst), salg,
+				      rng_crypto_instance(inst));
+	if (err)
+		goto free_inst;
+
+	inst->alg.base.cra_priority	= alg->cra_priority;
+	inst->alg.base.cra_blocksize	= alg->cra_blocksize;
+	inst->alg.base.cra_alignmask	= alg->cra_alignmask;
+
+	inst->alg.generate		= generate;
+	inst->alg.seed			= crypto_kdf_seed;
+	inst->alg.seedsize		= ds;
+
+	inst->alg.base.cra_init		= crypto_kdf_init_tfm;
+	inst->alg.base.cra_exit		= crypto_kdf_exit_tfm;
+	inst->alg.base.cra_ctxsize	= sizeof(struct crypto_kdf_ctx);
+
+	inst->free			= crypto_kdf_free;
+
+	err = rng_register_instance(tmpl, inst);
+
+	if (err) {
+		crypto_drop_spawn(rng_instance_ctx(inst));
+free_inst:
+		kfree(inst);
+	}
+
+out_put_alg:
+	crypto_mod_put(alg);
+	return err;
+}
+
+static int crypto_kdf_ctr_create(struct crypto_template *tmpl,
+				 struct rtattr **tb)
+{
+	return crypto_kdf_alloc_common(tmpl, tb, "kdf_ctr",
+				       crypto_kdf_ctr_generate);
+}
+
+static struct crypto_template crypto_kdf_ctr_tmpl = {
+	.name = "kdf_ctr",
+	.create = crypto_kdf_ctr_create,
+	.module = THIS_MODULE,
+};
+
+static int crypto_kdf_fb_create(struct crypto_template *tmpl,
+				struct rtattr **tb) {
+	return crypto_kdf_alloc_common(tmpl, tb, "kdf_fb",
+				       crypto_kdf_fb_generate);
+}
+
+static struct crypto_template crypto_kdf_fb_tmpl = {
+	.name = "kdf_fb",
+	.create = crypto_kdf_fb_create,
+	.module = THIS_MODULE,
+};
+
+static int crypto_kdf_dpi_create(struct crypto_template *tmpl,
+				 struct rtattr **tb) {
+	return crypto_kdf_alloc_common(tmpl, tb, "kdf_dpi",
+				       crypto_kdf_dpi_generate);
+}
+
+static struct crypto_template crypto_kdf_dpi_tmpl = {
+	.name = "kdf_dpi",
+	.create = crypto_kdf_dpi_create,
+	.module = THIS_MODULE,
+};
+
+static int __init crypto_kdf_init(void)
+{
+	int err = crypto_register_template(&crypto_kdf_ctr_tmpl);
+
+	if (err)
+		return err;
+
+	err = crypto_register_template(&crypto_kdf_fb_tmpl);
+	if (err) {
+		crypto_unregister_template(&crypto_kdf_ctr_tmpl);
+		return err;
+	}
+
+	err = crypto_register_template(&crypto_kdf_dpi_tmpl);
+	if (err) {
+		crypto_unregister_template(&crypto_kdf_ctr_tmpl);
+		crypto_unregister_template(&crypto_kdf_fb_tmpl);
+	}
+	return err;
+}
+
+static void __exit crypto_kdf_exit(void)
+{
+	crypto_unregister_template(&crypto_kdf_ctr_tmpl);
+	crypto_unregister_template(&crypto_kdf_fb_tmpl);
+	crypto_unregister_template(&crypto_kdf_dpi_tmpl);
+}
+
+module_init(crypto_kdf_init);
+module_exit(crypto_kdf_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("Key Derivation Function conformant to SP800-108");
+MODULE_ALIAS_CRYPTO("kdf_ctr");
+MODULE_ALIAS_CRYPTO("kdf_fb");
+MODULE_ALIAS_CRYPTO("kdf_dpi");
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 3/6] crypto: kdf - add known answer tests
  2019-01-16 11:06       ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Müller
  2019-01-16 11:07         ` [PATCH v2 1/6] crypto: add template handling for RNGs Stephan Müller
  2019-01-16 11:08         ` [PATCH v2 2/6] crypto: kdf - SP800-108 Key Derivation Function Stephan Müller
@ 2019-01-16 11:08         ` Stephan Müller
  2019-01-16 11:08         ` [PATCH v2 4/6] crypto: hkdf - HMAC-based Extract-and-Expand KDF Stephan Müller
                           ` (3 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-16 11:08 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Add known answer tests to the testmgr for the KDF (SP800-108) cipher.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/testmgr.c | 219 +++++++++++++++++++++++++++++++++++++++++++++++
 crypto/testmgr.h | 107 +++++++++++++++++++++++
 2 files changed, 326 insertions(+)

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 0f684a414acb..309819af55d8 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -110,6 +110,11 @@ struct drbg_test_suite {
 	unsigned int count;
 };
 
+struct kdf_test_suite {
+	const struct kdf_testvec *vecs;
+	unsigned int count;
+};
+
 struct akcipher_test_suite {
 	const struct akcipher_testvec *vecs;
 	unsigned int count;
@@ -133,6 +138,7 @@ struct alg_test_desc {
 		struct hash_test_suite hash;
 		struct cprng_test_suite cprng;
 		struct drbg_test_suite drbg;
+		struct kdf_test_suite kdf;
 		struct akcipher_test_suite akcipher;
 		struct kpp_test_suite kpp;
 	} suite;
@@ -2020,6 +2026,66 @@ static int drbg_cavs_test(const struct drbg_testvec *test, int pr,
 	return ret;
 }
 
+static int kdf_test(const struct kdf_testvec *test,
+		    const char *driver, u32 type, u32 mask)
+{
+	int ret = -EAGAIN;
+	struct crypto_rng *drng;
+	u8 *buf = kzalloc(test->expectedlen, GFP_KERNEL);
+
+	if (!buf)
+		return -ENOMEM;
+
+	drng = crypto_alloc_rng(driver, type | CRYPTO_ALG_INTERNAL, mask);
+	if (IS_ERR(drng)) {
+		pr_err("alg: kdf: could not allocate cipher handle "
+		       "for %s\n", driver);
+		kfree(buf);
+		return -ENOMEM;
+	}
+
+	ret = crypto_rng_reset(drng, test->K1, test->K1len);
+	if (ret) {
+		pr_err("alg: kdf: could not set key derivation key\n");
+		goto err;
+	}
+
+	ret = crypto_rng_generate(drng, test->context, test->contextlen,
+				  buf, test->expectedlen);
+	if (ret) {
+		pr_err("alg: kdf: could not obtain key data\n");
+		goto err;
+	}
+
+	ret = memcmp(test->expected, buf, test->expectedlen);
+	if (ret)
+		ret = -EINVAL;
+
+err:
+	crypto_free_rng(drng);
+	kfree(buf);
+	return ret;
+}
+
+static int alg_test_kdf(const struct alg_test_desc *desc, const char *driver,
+			u32 type, u32 mask)
+{
+	int err = 0;
+	unsigned int i = 0;
+	const struct kdf_testvec *template = desc->suite.kdf.vecs;
+	unsigned int tcount = desc->suite.kdf.count;
+
+	for (i = 0; i < tcount; i++) {
+		err = kdf_test(&template[i], driver, type, mask);
+		if (err) {
+			pr_err("alg: kdf: Test %d failed for %s\n",
+			       i, driver);
+			err = -EINVAL;
+			break;
+		}
+	}
+	return err;
+}
 
 static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver,
 			 u32 type, u32 mask)
@@ -3220,6 +3286,159 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.alg = "jitterentropy_rng",
 		.fips_allowed = 1,
 		.test = alg_test_null,
+	}, {
+		.alg = "kdf_ctr(cmac(aes))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(cmac(des3_ede))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(hmac(sha1))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(hmac(sha224))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(hmac(sha256))",
+		.test = alg_test_kdf,
+		.fips_allowed = 1,
+		.suite = {
+			.kdf = __VECS(kdf_ctr_hmac_sha256_tv_template)
+		}
+	}, {
+		.alg = "kdf_ctr(hmac(sha384))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(hmac(sha512))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(sha1)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(sha224)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(sha256)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(sha384)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_ctr(sha512)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(cmac(aes))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(cmac(des3_ede))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(hmac(sha1))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(hmac(sha224))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(hmac(sha256))",
+		.test = alg_test_kdf,
+		.fips_allowed = 1,
+		.suite = {
+			.kdf = __VECS(kdf_dpi_hmac_sha256_tv_template)
+		}
+	}, {
+		.alg = "kdf_dpi(hmac(sha384))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(hmac(sha512))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(sha1)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(sha224)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(sha256)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(sha384)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_dpi(sha512)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(cmac(aes))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(cmac(des3_ede))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(hmac(sha1))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(hmac(sha224))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(hmac(sha256))",
+		.test = alg_test_kdf,
+		.fips_allowed = 1,
+		.suite = {
+			.kdf = __VECS(kdf_fb_hmac_sha256_tv_template)
+		}
+	}, {
+		.alg = "kdf_fb(hmac(sha384))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(hmac(sha512))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(sha1)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(sha224)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(sha256)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(sha384)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "kdf_fb(sha512)",
+		.test = alg_test_null,
+		.fips_allowed = 1,
 	}, {
 		.alg = "kw(aes)",
 		.test = alg_test_skcipher,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index ca8e8ebef309..65fe3d4ef082 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -122,6 +122,15 @@ struct drbg_testvec {
 	size_t expectedlen;
 };
 
+struct kdf_testvec {
+	unsigned char *K1;
+	size_t K1len;
+	unsigned char *context;
+	size_t contextlen;
+	unsigned char *expected;
+	size_t expectedlen;
+};
+
 struct akcipher_testvec {
 	const unsigned char *key;
 	const unsigned char *m;
@@ -27892,6 +27901,104 @@ static const struct drbg_testvec drbg_nopr_ctr_aes128_tv_template[] = {
 	},
 };
 
+/*
+ * Test vector obtained from
+ * http://csrc.nist.gov/groups/STM/cavp/documents/KBKDF800-108/CounterMode.zip
+ */
+static const struct kdf_testvec kdf_ctr_hmac_sha256_tv_template[] = {
+	{
+		.K1 =	"\xdd\x1d\x91\xb7\xd9\x0b\x2b\xd3"
+			"\x13\x85\x33\xce\x92\xb2\x72\xfb"
+			"\xf8\xa3\x69\x31\x6a\xef\xe2\x42"
+			"\xe6\x59\xcc\x0a\xe2\x38\xaf\xe0",
+		.K1len = 32,
+		.context =
+			"\x01\x32\x2b\x96\xb3\x0a\xcd\x19"
+			"\x79\x79\x44\x4e\x46\x8e\x1c\x5c"
+			"\x68\x59\xbf\x1b\x1c\xf9\x51\xb7"
+			"\xe7\x25\x30\x3e\x23\x7e\x46\xb8"
+			"\x64\xa1\x45\xfa\xb2\x5e\x51\x7b"
+			"\x08\xf8\x68\x3d\x03\x15\xbb\x29"
+			"\x11\xd8\x0a\x0e\x8a\xba\x17\xf3"
+			"\xb4\x13\xfa\xac",
+		.contextlen = 60,
+		.expected =
+			"\x10\x62\x13\x42\xbf\xb0\xfd\x40"
+			"\x04\x6c\x0e\x29\xf2\xcf\xdb\xf0",
+		.expectedlen = 16
+	}
+};
+
+/*
+ * Test vector obtained from
+ * http://csrc.nist.gov/groups/STM/cavp/documents/KBKDF800-108/FeedbackModeNOzeroiv.zip
+ */
+static const struct kdf_testvec kdf_fb_hmac_sha256_tv_template[] = {
+	{
+		.K1 =	"\x93\xf6\x98\xe8\x42\xee\xd7\x53"
+			"\x94\xd6\x29\xd9\x57\xe2\xe8\x9c"
+			"\x6e\x74\x1f\x81\x0b\x62\x3c\x8b"
+			"\x90\x1e\x38\x37\x6d\x06\x8e\x7b",
+		.K1len = 32,
+		.context =
+			"\x9f\x57\x5d\x90\x59\xd3\xe0\xc0"
+			"\x80\x3f\x08\x11\x2f\x8a\x80\x6d"
+			"\xe3\xc3\x47\x19\x12\xcd\xf4\x2b"
+			"\x09\x53\x88\xb1\x4b\x33\x50\x8e"
+			"\x53\xb8\x9c\x18\x69\x0e\x20\x57"
+			"\xa1\xd1\x67\x82\x2e\x63\x6d\xe5"
+			"\x0b\xe0\x01\x85\x32\xc4\x31\xf7"
+			"\xf5\xe3\x7f\x77\x13\x92\x20\xd5"
+			"\xe0\x42\x59\x9e\xbe\x26\x6a\xf5"
+			"\x76\x7e\xe1\x8c\xd2\xc5\xc1\x9a"
+			"\x1f\x0f\x80",
+		.contextlen = 83,
+		.expected =
+			"\xbd\x14\x76\xf4\x3a\x4e\x31\x57"
+			"\x47\xcf\x59\x18\xe0\xea\x5b\xc0"
+			"\xd9\x87\x69\x45\x74\x77\xc3\xab"
+			"\x18\xb7\x42\xde\xf0\xe0\x79\xa9"
+			"\x33\xb7\x56\x36\x5a\xfb\x55\x41"
+			"\xf2\x53\xfe\xe4\x3c\x6f\xd7\x88"
+			"\xa4\x40\x41\x03\x85\x09\xe9\xee"
+			"\xb6\x8f\x7d\x65\xff\xbb\x5f\x95",
+		.expectedlen = 64
+	}
+};
+
+/*
+ * Test vector obtained from
+ * http://csrc.nist.gov/groups/STM/cavp/documents/KBKDF800-108/PipelineModewithCounter.zip
+ */
+static const struct kdf_testvec kdf_dpi_hmac_sha256_tv_template[] = {
+	{
+		.K1 =	"\x02\xd3\x6f\xa0\x21\xc2\x0d\xdb"
+			"\xde\xe4\x69\xf0\x57\x94\x68\xba"
+			"\xe5\xcb\x13\xb5\x48\xb6\xc6\x1c"
+			"\xdf\x9d\x3e\xc4\x19\x11\x1d\xe2",
+		.K1len = 32,
+		.context =
+			"\x85\xab\xe3\x8b\xf2\x65\xfb\xdc"
+			"\x64\x45\xae\x5c\x71\x15\x9f\x15"
+			"\x48\xc7\x3b\x7d\x52\x6a\x62\x31"
+			"\x04\x90\x4a\x0f\x87\x92\x07\x0b"
+			"\x3d\xf9\x90\x2b\x96\x69\x49\x04"
+			"\x25\xa3\x85\xea\xdb\x0f\x9c\x76"
+			"\xe4\x6f\x0f",
+		.contextlen = 51,
+		.expected =
+			"\xd6\x9f\x74\xf5\x18\xc9\xf6\x4f"
+			"\x90\xa0\xbe\xeb\xab\x69\xf6\x89"
+			"\xb7\x3b\x5c\x13\xeb\x0f\x86\x0a"
+			"\x95\xca\xd7\xd9\x81\x4f\x8c\x50"
+			"\x6e\xb7\xb1\x79\xa5\xc5\xb4\x46"
+			"\x6a\x9e\xc1\x54\xc3\xbf\x1c\x13"
+			"\xef\xd6\xec\x0d\x82\xb0\x2c\x29"
+			"\xaf\x2c\x69\x02\x99\xed\xc4\x53",
+		.expectedlen = 64
+	}
+};
+
 /* Cast5 test vectors from RFC 2144 */
 static const struct cipher_testvec cast5_tv_template[] = {
 	{
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 4/6] crypto: hkdf - HMAC-based Extract-and-Expand KDF
  2019-01-16 11:06       ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Müller
                           ` (2 preceding siblings ...)
  2019-01-16 11:08         ` [PATCH v2 3/6] crypto: kdf - add known answer tests Stephan Müller
@ 2019-01-16 11:08         ` Stephan Müller
  2019-01-16 11:09         ` [PATCH v2 5/6] crypto: hkdf - add known answer tests Stephan Müller
                           ` (2 subsequent siblings)
  6 siblings, 0 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-16 11:08 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

The HMAC-based Extract-and-Expand Key Derivation Function is conformant
to RFC5869.

The extraction phase can be invoked separately from the expansion phase.
This implies that the once a key is set and thus the extraction phase was
applied, the expansion phase can be invoked multiple times.

The HKDF implementation does not restrict the type of keyed message
digest it is instantiated with. RFC5869 specifies HMAC-SHA as the only
keyed message digest, though. From a cryptographic point of view, using
other keyed message digests would result in an equally strong KDF.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/Kconfig  |   6 ++
 crypto/Makefile |   1 +
 crypto/hkdf.c   | 272 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 279 insertions(+)
 create mode 100644 crypto/hkdf.c

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 7c0336c9ba9c..c25b2033321a 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -568,6 +568,12 @@ config CRYPTO_KDF_SP800108
 	  Support for KDF compliant to SP800-108. All three types of
 	  KDF specified in SP800-108 are implemented.
 
+config CRYPTO_HKDF
+	tristate "HMAC-based Extract-and-Expand Key Derivation Function (HKDF)"
+	select CRYPTO_RNG
+	help
+	  Support for KDF conformant to RFC5869.
+
 config CRYPTO_XCBC
 	tristate "XCBC support"
 	select CRYPTO_HASH
diff --git a/crypto/Makefile b/crypto/Makefile
index eead7ec9fd8e..80363b8cbf6c 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -59,6 +59,7 @@ crypto_user-$(CONFIG_CRYPTO_STATS) += crypto_user_stat.o
 obj-$(CONFIG_CRYPTO_CMAC) += cmac.o
 obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
 obj-$(CONFIG_CRYPTO_KDF_SP800108) += kdf_sp800108.o
+obj-$(CONFIG_CRYPTO_HKDF) += hkdf.o
 obj-$(CONFIG_CRYPTO_VMAC) += vmac.o
 obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
 obj-$(CONFIG_CRYPTO_NULL2) += crypto_null.o
diff --git a/crypto/hkdf.c b/crypto/hkdf.c
new file mode 100644
index 000000000000..2f392c71c85b
--- /dev/null
+++ b/crypto/hkdf.c
@@ -0,0 +1,272 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * HMAC-based Extract-and-Expand Key Derivation Function (conformant to RFC5869)
+ *
+ * Copyright (C) 2019, Stephan Mueller <smueller@chronox.de>
+ */
+
+/*
+ * The HKDF extract phase is applied with crypto_rng_reset().
+ * The HKDF expand phase is applied with crypto_rng_generate().
+ */
+
+#include <asm/unaligned.h>
+#include <linux/module.h>
+#include <crypto/rng.h>
+#include <crypto/internal/rng.h>
+#include <crypto/hash.h>
+#include <crypto/internal/hash.h>
+
+struct crypto_hkdf_ctx {
+	struct crypto_shash *kmd;
+};
+
+#define CRYPTO_HKDF_MAX_DIGESTSIZE	64
+
+static inline void crypto_kdf_init_desc(struct shash_desc *desc,
+					struct crypto_shash *kmd)
+{
+	desc->tfm = kmd;
+	desc->flags = 0;
+}
+
+/*
+ * HKDF expand phase
+ */
+static int crypto_hkdf_generate(struct crypto_rng *rng,
+				const u8 *info, unsigned int infolen,
+				u8 *dst, unsigned int dlen)
+{
+	const struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	struct crypto_shash *kmd = ctx->kmd;
+	SHASH_DESC_ON_STACK(desc, kmd);
+	const unsigned int h = crypto_shash_digestsize(kmd);
+	int err = 0;
+	u8 *dst_orig = dst;
+	const u8 *prev = NULL;
+	u8 ctr = 0x01;
+
+	if (dlen > h * 255)
+		return -EINVAL;
+
+	crypto_kdf_init_desc(desc, kmd);
+
+	/* T(1) and following */
+	while (dlen) {
+		err = crypto_shash_init(desc);
+		if (err)
+			goto out;
+
+		if (prev) {
+			err = crypto_shash_update(desc, prev, h);
+			if (err)
+				goto out;
+		}
+
+		if (info) {
+			err = crypto_shash_update(desc, info, infolen);
+			if (err)
+				goto out;
+		}
+
+		if (dlen < h) {
+			u8 tmpbuffer[CRYPTO_HKDF_MAX_DIGESTSIZE];
+
+			err = crypto_shash_finup(desc, &ctr, 1, tmpbuffer);
+			if (err)
+				goto out;
+			memcpy(dst, tmpbuffer, dlen);
+			memzero_explicit(tmpbuffer, h);
+			goto out;
+		}
+
+		err = crypto_shash_finup(desc, &ctr, 1, dst);
+		if (err)
+			goto out;
+
+		prev = dst;
+		dst += h;
+		dlen -= h;
+		ctr++;
+	}
+
+out:
+	if (err)
+		memzero_explicit(dst_orig, dlen);
+	shash_desc_zero(desc);
+	return err;
+}
+
+/*
+ * HKDF extract phase.
+ *
+ * The seed is defined to be a concatenation of the salt and the IKM.
+ * The data buffer is pre-pended by a word which provides an u32 value
+ * with the length of the salt. Thus, the buffer length - salt length is the
+ * IKM length.
+ */
+static int crypto_hkdf_seed(struct crypto_rng *rng,
+			    const u8 *seed, unsigned int slen)
+{
+	const struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(crypto_rng_tfm(rng));
+	struct crypto_shash *kmd = ctx->kmd;
+	SHASH_DESC_ON_STACK(desc, kmd);
+	u32 saltlen;
+	unsigned int h = crypto_shash_digestsize(kmd);
+	int err;
+	const u8 null_salt[CRYPTO_HKDF_MAX_DIGESTSIZE] = { 0 };
+	u8 prk[CRYPTO_HKDF_MAX_DIGESTSIZE];
+
+	if (slen < sizeof(saltlen))
+		return -EINVAL;
+
+	saltlen = get_unaligned((u32 *)seed);
+
+	seed += sizeof(saltlen);
+	slen -= sizeof(saltlen);
+
+	if (slen < saltlen)
+		return -EINVAL;
+
+	crypto_kdf_init_desc(desc, kmd);
+
+	/* Set the salt as HMAC key */
+	if (saltlen)
+		err = crypto_shash_setkey(kmd, seed, saltlen);
+	else
+		err = crypto_shash_setkey(kmd, null_salt, h);
+	if (err)
+		return err;
+
+	/* Extract the PRK */
+	err = crypto_shash_digest(desc, seed + saltlen, slen - saltlen, prk);
+	if (err)
+		goto err;
+
+	/* Set the PRK for the expand phase */
+	err = crypto_shash_setkey(kmd, prk, h);
+
+err:
+	shash_desc_zero(desc);
+	memzero_explicit(prk, h);
+	return err;
+}
+
+static int crypto_hkdf_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+	struct crypto_shash_spawn *spawn = crypto_instance_ctx(inst);
+	struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_shash *kmd;
+
+	kmd = crypto_spawn_shash(spawn);
+	if (IS_ERR(kmd))
+		return PTR_ERR(kmd);
+
+	ctx->kmd = kmd;
+
+	return 0;
+}
+
+static void crypto_hkdf_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_hkdf_ctx *ctx = crypto_tfm_ctx(tfm);
+
+	crypto_free_shash(ctx->kmd);
+}
+
+static void crypto_kdf_free(struct rng_instance *inst)
+{
+	crypto_drop_spawn(rng_instance_ctx(inst));
+	kfree(inst);
+}
+
+static int crypto_hkdf_create(struct crypto_template *tmpl, struct rtattr **tb)
+{
+	struct rng_instance *inst;
+	struct crypto_alg *alg;
+	struct shash_alg *salg;
+	int err;
+	unsigned int ds, ss;
+
+	err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_RNG);
+	if (err)
+		return err;
+
+	salg = shash_attr_alg(tb[1], 0, 0);
+	if (IS_ERR(salg))
+		return PTR_ERR(salg);
+
+	/* Require a keyed message digest */
+	if (!salg->setkey)
+		return -EOPNOTSUPP;
+
+	ds = salg->digestsize;
+	/* Hashes with no digest size are not allowed for KDFs. */
+	if (!ds || WARN_ON(ds > CRYPTO_HKDF_MAX_DIGESTSIZE))
+		return -EOPNOTSUPP;
+
+	ss = salg->statesize;
+	alg = &salg->base;
+
+	inst = rng_alloc_instance("hkdf", alg);
+	err = PTR_ERR(inst);
+	if (IS_ERR(inst))
+		goto out_put_alg;
+
+	err = crypto_init_shash_spawn(rng_instance_ctx(inst), salg,
+				      rng_crypto_instance(inst));
+	if (err)
+		goto free_inst;
+
+	inst->alg.base.cra_priority	= alg->cra_priority;
+	inst->alg.base.cra_blocksize	= alg->cra_blocksize;
+	inst->alg.base.cra_alignmask	= alg->cra_alignmask;
+
+	inst->alg.generate		= crypto_hkdf_generate;
+	inst->alg.seed			= crypto_hkdf_seed;
+
+	inst->alg.base.cra_init		= crypto_hkdf_init_tfm;
+	inst->alg.base.cra_exit		= crypto_hkdf_exit_tfm;
+	inst->alg.base.cra_ctxsize	= sizeof(struct crypto_hkdf_ctx);
+
+	inst->free			= crypto_kdf_free;
+
+	err = rng_register_instance(tmpl, inst);
+
+	if (err) {
+		crypto_drop_spawn(rng_instance_ctx(inst));
+free_inst:
+		kfree(inst);
+	}
+
+
+out_put_alg:
+	crypto_mod_put(alg);
+	return err;
+}
+
+static struct crypto_template crypto_hkdf_tmpl = {
+	.name = "hkdf",
+	.create = crypto_hkdf_create,
+	.module = THIS_MODULE,
+};
+
+static int __init crypto_hkdf_init(void)
+{
+	return crypto_register_template(&crypto_hkdf_tmpl);
+}
+
+static void __exit crypto_hkdf_exit(void)
+{
+	crypto_unregister_template(&crypto_hkdf_tmpl);
+}
+
+module_init(crypto_hkdf_init);
+module_exit(crypto_hkdf_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>");
+MODULE_DESCRIPTION("HKDF HMAC-based Extract-and-Expand Key Derivation Function  (conformant to RFC5869)");
+MODULE_ALIAS_CRYPTO("hkdf");
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 5/6] crypto: hkdf - add known answer tests
  2019-01-16 11:06       ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Müller
                           ` (3 preceding siblings ...)
  2019-01-16 11:08         ` [PATCH v2 4/6] crypto: hkdf - HMAC-based Extract-and-Expand KDF Stephan Müller
@ 2019-01-16 11:09         ` Stephan Müller
  2019-01-16 11:09         ` [PATCH v2 6/6] crypto: tcrypt - add KDF test invocation Stephan Müller
  2019-01-28 10:07         ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Mueller
  6 siblings, 0 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-16 11:09 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Add known answer tests to the testmgr for the HKDF (RFC5869) cipher.

The known answer tests are derived from RFC 5869 appendix A.

Note, the HKDF is considered to be a FIPS 140-2 allowed (not approved)
cipher as of now. Yet, an allowed cipher is usable under FIPS 140-2
rules.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/testmgr.c | 26 ++++++++++++++
 crypto/testmgr.h | 91 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 117 insertions(+)

diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 309819af55d8..0b06721a70df 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -3189,6 +3189,32 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.suite = {
 			.hash = __VECS(ghash_tv_template)
 		}
+	}, {
+		.alg = "hkdf(hmac(sha1))",
+		.test = alg_test_kdf,
+		.fips_allowed = 1,
+		.suite = {
+			.kdf = __VECS(hkdf_hmac_sha1_tv_template)
+		}
+	}, {
+		.alg = "hkdf(hmac(sha224))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "hkdf(hmac(sha256))",
+		.test = alg_test_kdf,
+		.fips_allowed = 1,
+		.suite = {
+			.kdf = __VECS(hkdf_hmac_sha256_tv_template)
+		}
+	}, {
+		.alg = "hkdf(hmac(sha384))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
+	}, {
+		.alg = "hkdf(hmac(sha512))",
+		.test = alg_test_null,
+		.fips_allowed = 1,
 	}, {
 		.alg = "hmac(md5)",
 		.test = alg_test_hash,
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 65fe3d4ef082..7ffff184fba2 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -27999,6 +27999,97 @@ static const struct kdf_testvec kdf_dpi_hmac_sha256_tv_template[] = {
 	}
 };
 
+/* Test vectors from RFC 5869 appendix A */
+static const struct kdf_testvec hkdf_hmac_sha256_tv_template[] = {
+	{
+		.K1 =
+#ifdef __LITTLE_ENDIAN
+			"\x0d\x00\x00\x00"		/* salt length */
+#else
+			"\x00\x00\x00\x0d"		/* salt length */
+#endif
+			"\x00\x01\x02\x03\x04\x05\x06\x07"
+			"\x08\x09\x0a\x0b\x0c"		/* salt */
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b",	/* IKM */
+		.K1len = 39,
+		.context =
+			"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			"\xf8\xf9",
+		.contextlen = 10,
+		.expected =
+			"\x3c\xb2\x5f\x25\xfa\xac\xd5\x7a"
+			"\x90\x43\x4f\x64\xd0\x36\x2f\x2a"
+			"\x2d\x2d\x0a\x90\xcf\x1a\x5a\x4c"
+			"\x5d\xb0\x2d\x56\xec\xc4\xc5\xbf"
+			"\x34\x00\x72\x08\xd5\xb8\x87\x18"
+			"\x58\x65",
+		.expectedlen = 42
+	}, {
+		.K1 =	"\x00\x00\x00\x00"		/* salt length */
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b",	/* IKM */
+		.K1len = 26,
+		.context = NULL,
+		.contextlen = 0,
+		.expected =
+			"\x8d\xa4\xe7\x75\xa5\x63\xc1\x8f"
+			"\x71\x5f\x80\x2a\x06\x3c\x5a\x31"
+			"\xb8\xa1\x1f\x5c\x5e\xe1\x87\x9e"
+			"\xc3\x45\x4e\x5f\x3c\x73\x8d\x2d"
+			"\x9d\x20\x13\x95\xfa\xa4\xb6\x1a"
+			"\x96\xc8",
+		.expectedlen = 42
+	}
+};
+
+/* Test vectors from RFC 5869 appendix A */
+static const struct kdf_testvec hkdf_hmac_sha1_tv_template[] = {
+	{
+		.K1 =
+#ifdef __LITTLE_ENDIAN
+			"\x0d\x00\x00\x00"		/* salt length */
+#else
+			"\x00\x00\x00\x0d"		/* salt length */
+#endif
+			"\x00\x01\x02\x03\x04\x05\x06\x07"
+			"\x08\x09\x0a\x0b\x0c"		/* salt */
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b",			/* IKM */
+		.K1len = 28,
+		.context =
+			"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+			"\xf8\xf9",
+		.contextlen = 10,
+		.expected =
+			"\x08\x5a\x01\xea\x1b\x10\xf3\x69"
+			"\x33\x06\x8b\x56\xef\xa5\xad\x81"
+			"\xa4\xf1\x4b\x82\x2f\x5b\x09\x15"
+			"\x68\xa9\xcd\xd4\xf1\x55\xfd\xa2"
+			"\xc2\x2e\x42\x24\x78\xd3\x05\xf3"
+			"\xf8\x96",
+		.expectedlen = 42
+	}, {
+		.K1 =	"\x00\x00\x00\x00"		/* salt length */
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
+			"\x0b\x0b\x0b\x0b\x0b\x0b",	/* IKM */
+		.K1len = 26,
+		.context = NULL,
+		.contextlen = 0,
+		.expected =
+			"\x0a\xc1\xaf\x70\x02\xb3\xd7\x61"
+			"\xd1\xe5\x52\x98\xda\x9d\x05\x06"
+			"\xb9\xae\x52\x05\x72\x20\xa3\x06"
+			"\xe0\x7b\x6b\x87\xe8\xdf\x21\xd0"
+			"\xea\x00\x03\x3d\xe0\x39\x84\xd3"
+			"\x49\x18",
+		.expectedlen = 42
+	}
+};
+
 /* Cast5 test vectors from RFC 2144 */
 static const struct cipher_testvec cast5_tv_template[] = {
 	{
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH v2 6/6] crypto: tcrypt - add KDF test invocation
  2019-01-16 11:06       ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Müller
                           ` (4 preceding siblings ...)
  2019-01-16 11:09         ` [PATCH v2 5/6] crypto: hkdf - add known answer tests Stephan Müller
@ 2019-01-16 11:09         ` Stephan Müller
  2019-01-28 10:07         ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Mueller
  6 siblings, 0 replies; 36+ messages in thread
From: Stephan Müller @ 2019-01-16 11:09 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Enable testing of the SP800-108 and RFC5869 KDFs.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 crypto/tcrypt.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index e7fb87e114a5..5606e59e80ec 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -2054,6 +2054,14 @@ static int do_test(const char *alg, u32 type, u32 mask, int m, u32 num_mb)
 		ret += tcrypt_test("cbc(sm4)");
 		ret += tcrypt_test("ctr(sm4)");
 		break;
+	case 192:
+		ret += tcrypt_test("kdf_ctr(hmac(sha256))");
+		ret += tcrypt_test("kdf_dpi(hmac(sha256))");
+		ret += tcrypt_test("kdf_fb(hmac(sha256))");
+		break;
+	case 193:
+		ret += tcrypt_test("hkdf(hmac(sha256))");
+		break;
 	case 200:
 		test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
 				speed_template_16_24_32);
-- 
2.20.1

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 0/6] General Key Derivation Function Support
  2019-01-16 11:06       ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Müller
                           ` (5 preceding siblings ...)
  2019-01-16 11:09         ` [PATCH v2 6/6] crypto: tcrypt - add KDF test invocation Stephan Müller
@ 2019-01-28 10:07         ` Stephan Mueller
  2019-01-30 10:08           ` Herbert Xu
  6 siblings, 1 reply; 36+ messages in thread
From: Stephan Mueller @ 2019-01-28 10:07 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Am Mittwoch, 16. Januar 2019, 12:06:54 CET schrieb Stephan Müller:

Hi Herbert,

> Changes v2:
> * Incorporation of all comments from Eric Biggers
> 
> Stephan Mueller (6):
>   crypto: add template handling for RNGs
>   crypto: kdf - SP800-108 Key Derivation Function
>   crypto: kdf - add known answer tests
>   crypto: hkdf - HMAC-based Extract-and-Expand KDF
>   crypto: hkdf - add known answer tests
>   crypto: tcrypt - add KDF test invocation
> 
>  crypto/Kconfig                |  13 +
>  crypto/Makefile               |   2 +
>  crypto/hkdf.c                 | 272 +++++++++++++++++++
>  crypto/kdf_sp800108.c         | 491 ++++++++++++++++++++++++++++++++++
>  crypto/rng.c                  |  44 +++
>  crypto/tcrypt.c               |   8 +
>  crypto/testmgr.c              | 245 +++++++++++++++++
>  crypto/testmgr.h              | 198 ++++++++++++++
>  include/crypto/internal/rng.h |  26 ++
>  9 files changed, 1299 insertions(+)
>  create mode 100644 crypto/hkdf.c
>  create mode 100644 crypto/kdf_sp800108.c

Do you happen to have any comments on this patch set?

Ciao
Stephan



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 0/6] General Key Derivation Function Support
  2019-01-28 10:07         ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Mueller
@ 2019-01-30 10:08           ` Herbert Xu
  2019-01-30 14:39             ` Stephan Mueller
  0 siblings, 1 reply; 36+ messages in thread
From: Herbert Xu @ 2019-01-30 10:08 UTC (permalink / raw)
  To: Stephan Mueller
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

On Mon, Jan 28, 2019 at 11:07:28AM +0100, Stephan Mueller wrote:
> Am Mittwoch, 16. Januar 2019, 12:06:54 CET schrieb Stephan Müller:
> 
> Hi Herbert,
> 
> > Changes v2:
> > * Incorporation of all comments from Eric Biggers
> > 
> > Stephan Mueller (6):
> >   crypto: add template handling for RNGs
> >   crypto: kdf - SP800-108 Key Derivation Function
> >   crypto: kdf - add known answer tests
> >   crypto: hkdf - HMAC-based Extract-and-Expand KDF
> >   crypto: hkdf - add known answer tests
> >   crypto: tcrypt - add KDF test invocation
> > 
> >  crypto/Kconfig                |  13 +
> >  crypto/Makefile               |   2 +
> >  crypto/hkdf.c                 | 272 +++++++++++++++++++
> >  crypto/kdf_sp800108.c         | 491 ++++++++++++++++++++++++++++++++++
> >  crypto/rng.c                  |  44 +++
> >  crypto/tcrypt.c               |   8 +
> >  crypto/testmgr.c              | 245 +++++++++++++++++
> >  crypto/testmgr.h              | 198 ++++++++++++++
> >  include/crypto/internal/rng.h |  26 ++
> >  9 files changed, 1299 insertions(+)
> >  create mode 100644 crypto/hkdf.c
> >  create mode 100644 crypto/kdf_sp800108.c
> 
> Do you happen to have any comments on this patch set?

I'm still not convinced why this needs to go into the crypto API
instead of being hosted in a helper which should achieve pretty
much the same result.

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] 36+ messages in thread

* Re: [PATCH v2 0/6] General Key Derivation Function Support
  2019-01-30 10:08           ` Herbert Xu
@ 2019-01-30 14:39             ` Stephan Mueller
  2019-02-08  7:45               ` Herbert Xu
  0 siblings, 1 reply; 36+ messages in thread
From: Stephan Mueller @ 2019-01-30 14:39 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Am Mittwoch, 30. Januar 2019, 11:08:54 CET schrieb Herbert Xu:

Hi Herbert,

> I'm still not convinced why this needs to go into the crypto API
> instead of being hosted in a helper which should achieve pretty
> much the same result.

How do you propose to handle the FIPS 140-2 related requirements of enforcing 
the integrity test result and the known-answer self tests?

Thanks
Stephan



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 0/6] General Key Derivation Function Support
  2019-01-30 14:39             ` Stephan Mueller
@ 2019-02-08  7:45               ` Herbert Xu
  2019-02-08  8:00                 ` Stephan Mueller
  0 siblings, 1 reply; 36+ messages in thread
From: Herbert Xu @ 2019-02-08  7:45 UTC (permalink / raw)
  To: Stephan Mueller
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

On Wed, Jan 30, 2019 at 03:39:10PM +0100, Stephan Mueller wrote:
> Am Mittwoch, 30. Januar 2019, 11:08:54 CET schrieb Herbert Xu:
> 
> Hi Herbert,
> 
> > I'm still not convinced why this needs to go into the crypto API
> > instead of being hosted in a helper which should achieve pretty
> > much the same result.
> 
> How do you propose to handle the FIPS 140-2 related requirements of enforcing 
> the integrity test result and the known-answer self tests?

We could easily add self-tests for the helper.

Cheers,
-- 
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] 36+ messages in thread

* Re: [PATCH v2 0/6] General Key Derivation Function Support
  2019-02-08  7:45               ` Herbert Xu
@ 2019-02-08  8:00                 ` Stephan Mueller
  2019-02-08  8:05                   ` Herbert Xu
  0 siblings, 1 reply; 36+ messages in thread
From: Stephan Mueller @ 2019-02-08  8:00 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Am Freitag, 8. Februar 2019, 08:45:58 CET schrieb Herbert Xu:

Hi Herbert,

> We could easily add self-tests for the helper.

Thanks for the clarification. And do you have a suggestion how we can should 
ensure that the self-tests are run only once?

Also, shall we add the signature verification enforcemnt to the helper as 
well?


Ciao
Stephan



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 0/6] General Key Derivation Function Support
  2019-02-08  8:00                 ` Stephan Mueller
@ 2019-02-08  8:05                   ` Herbert Xu
  2019-02-08  8:17                     ` Stephan Mueller
  0 siblings, 1 reply; 36+ messages in thread
From: Herbert Xu @ 2019-02-08  8:05 UTC (permalink / raw)
  To: Stephan Mueller
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

On Fri, Feb 08, 2019 at 09:00:59AM +0100, Stephan Mueller wrote:
>
> Thanks for the clarification. And do you have a suggestion how we can should 
> ensure that the self-tests are run only once?

Making it run at kernel init time should be good enough.

> Also, shall we add the signature verification enforcemnt to the helper as 
> well?

What do you mean by that?

Cheers,
-- 
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] 36+ messages in thread

* Re: [PATCH v2 0/6] General Key Derivation Function Support
  2019-02-08  8:05                   ` Herbert Xu
@ 2019-02-08  8:17                     ` Stephan Mueller
  2019-02-19  5:44                       ` Herbert Xu
  0 siblings, 1 reply; 36+ messages in thread
From: Stephan Mueller @ 2019-02-08  8:17 UTC (permalink / raw)
  To: Herbert Xu
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

Am Freitag, 8. Februar 2019, 09:05:47 CET schrieb Herbert Xu:

Hi Herbert,
> 
> > Also, shall we add the signature verification enforcemnt to the helper as
> > well?
> 
> What do you mean by that?

We need to invoke the function crypto_check_module_sig when the module is 
loaded. Do you have any concerns invoking it from the module init function?

Ciao
Stephan



^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH v2 0/6] General Key Derivation Function Support
  2019-02-08  8:17                     ` Stephan Mueller
@ 2019-02-19  5:44                       ` Herbert Xu
  0 siblings, 0 replies; 36+ messages in thread
From: Herbert Xu @ 2019-02-19  5:44 UTC (permalink / raw)
  To: Stephan Mueller
  Cc: Eric Biggers, James Bottomley, Andy Lutomirski, Lee, Chun-Yi,
	Rafael J . Wysocki, Pavel Machek, linux-kernel, linux-pm,
	keyrings, Rafael J. Wysocki, Chen Yu, Oliver Neukum, Ryan Chen,
	David Howells, Giovanni Gherdovich, Randy Dunlap, Jann Horn,
	Andy Lutomirski, linux-crypto

On Fri, Feb 08, 2019 at 09:17:50AM +0100, Stephan Mueller wrote:
> > 
> > > Also, shall we add the signature verification enforcemnt to the helper as
> > > well?
> > 
> > What do you mean by that?
> 
> We need to invoke the function crypto_check_module_sig when the module is 
> loaded. Do you have any concerns invoking it from the module init function?

Which module's signature are you going to check? If it's the
underlying crypto API modules then wouldn't they have been
checked already when they were registered?

Cheers,
-- 
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] 36+ messages in thread

end of thread, other threads:[~2019-02-19  5:46 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <20190103143227.9138-1-jlee@suse.com>
     [not found] ` <1894062.aDvIuj92vB@tauon.chronox.de>
     [not found]   ` <20190109082103.GA8586@sol.localdomain>
2019-01-11 19:08     ` [PATCH 0/6] General Key Derivation Function Support Stephan Müller
2019-01-11 19:09       ` [PATCH 1/6] crypto: add template handling for RNGs Stephan Müller
2019-01-11 19:10       ` [PATCH 2/6] crypto: kdf - SP800-108 Key Derivation Function Stephan Müller
2019-01-12  5:27         ` Eric Biggers
2019-01-14  9:31           ` Stephan Müller
2019-01-11 19:10       ` [PATCH 3/6] crypto: kdf - add known answer tests Stephan Müller
2019-01-12  5:26         ` Eric Biggers
2019-01-14  9:26           ` Stephan Müller
2019-01-11 19:10       ` [PATCH 4/6] crypto: hkdf - RFC5869 Key Derivation Function Stephan Müller
2019-01-12  5:12         ` Eric Biggers
2019-01-12  9:55           ` Herbert Xu
2019-01-13  7:56             ` Stephan Müller
2019-01-13 16:52               ` James Bottomley
2019-01-14  9:30           ` Stephan Müller
2019-01-14 17:53             ` Eric Biggers
2019-01-14 18:44               ` Stephan Mueller
2019-01-11 19:10       ` [PATCH 5/6] crypto: hkdf - add known answer tests Stephan Müller
2019-01-12  5:19         ` Eric Biggers
2019-01-14  9:25           ` Stephan Müller
2019-01-14 17:44             ` Eric Biggers
2019-01-11 19:11       ` [PATCH 6/6] crypto: tcrypt - add KDF test invocation Stephan Müller
2019-01-16 11:06       ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Müller
2019-01-16 11:07         ` [PATCH v2 1/6] crypto: add template handling for RNGs Stephan Müller
2019-01-16 11:08         ` [PATCH v2 2/6] crypto: kdf - SP800-108 Key Derivation Function Stephan Müller
2019-01-16 11:08         ` [PATCH v2 3/6] crypto: kdf - add known answer tests Stephan Müller
2019-01-16 11:08         ` [PATCH v2 4/6] crypto: hkdf - HMAC-based Extract-and-Expand KDF Stephan Müller
2019-01-16 11:09         ` [PATCH v2 5/6] crypto: hkdf - add known answer tests Stephan Müller
2019-01-16 11:09         ` [PATCH v2 6/6] crypto: tcrypt - add KDF test invocation Stephan Müller
2019-01-28 10:07         ` [PATCH v2 0/6] General Key Derivation Function Support Stephan Mueller
2019-01-30 10:08           ` Herbert Xu
2019-01-30 14:39             ` Stephan Mueller
2019-02-08  7:45               ` Herbert Xu
2019-02-08  8:00                 ` Stephan Mueller
2019-02-08  8:05                   ` Herbert Xu
2019-02-08  8:17                     ` Stephan Mueller
2019-02-19  5:44                       ` Herbert Xu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).