Linux cryptographic layer development
 help / color / mirror / Atom feed
* [PATCH v5] KEYS: add SP800-56A KDF support for DH
From: Stephan Mueller @ 2016-08-19 18:39 UTC (permalink / raw)
  To: herbert, mathew.j.martineau, dhowells; +Cc: linux-crypto, keyrings

Hi,

This patch now folds the KDF into the keys support as requested by
Herbert. The caller can only supply the hash name used for the KDF.

Note, the KDF implementation is identical to the kdf_ctr() support in
the now unneeded KDF patches to the kernel crypto API.

The new patch also changes the variable name from kdfname to hashname.

Also, the patch adds a missing semicolon.

Finally, the patch adds a guard against compiling the compat code
if the general Linux kernel configuration does not have the compat
code enabled. Without that guard, compilation warnings are seen.

---8<---

SP800-56A defines the use of DH with key derivation function based on a
counter. The input to the KDF is defined as (DH shared secret || other
information). The value for the "other information" is to be provided by
the caller.

The KDF is implemented using the hash support from the kernel crypto API.
The implementation uses the symmetric hash support as the input to the
hash operation is usually very small. The caller is allowed to specify
the hash name that he wants to use to derive the key material allowing
the use of all supported hashes provided with the kernel crypto API.

As the KDF implements the proper truncation of the DH shared secret to
the requested size, this patch fills the caller buffer up to its size.

The patch is tested with a new test added to the keyutils user space
code which uses a CAVS test vector testing the compliance with
SP800-56A.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 Documentation/security/keys.txt |  34 ++++--
 include/linux/compat.h          |   7 ++
 include/uapi/linux/keyctl.h     |   7 ++
 security/keys/Kconfig           |   1 +
 security/keys/Makefile          |   3 +-
 security/keys/compat.c          |   5 +-
 security/keys/compat_dh.c       |  38 +++++++
 security/keys/dh.c              | 222 +++++++++++++++++++++++++++++++++++++---
 security/keys/internal.h        |  24 ++++-
 security/keys/keyctl.c          |   2 +-
 10 files changed, 317 insertions(+), 26 deletions(-)
 create mode 100644 security/keys/compat_dh.c

diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 3849814..58fcae7 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -827,7 +827,7 @@ The keyctl syscall functions are:
 
        long keyctl(KEYCTL_DH_COMPUTE, struct keyctl_dh_params *params,
 		   char *buffer, size_t buflen,
-		   void *reserved);
+		   struct keyctl_kdf_params *kdf);
 
      The params struct contains serial numbers for three keys:
 
@@ -844,18 +844,36 @@ The keyctl syscall functions are:
      public key.  If the base is the remote public key, the result is
      the shared secret.
 
-     The reserved argument must be set to NULL.
+     If the parameter kdf is NULL, the following applies:
 
-     The buffer length must be at least the length of the prime, or zero.
+	 - The buffer length must be at least the length of the prime, or zero.
 
-     If the buffer length is nonzero, the length of the result is
-     returned when it is successfully calculated and copied in to the
-     buffer. When the buffer length is zero, the minimum required
-     buffer length is returned.
+	 - If the buffer length is nonzero, the length of the result is
+	   returned when it is successfully calculated and copied in to the
+	   buffer. When the buffer length is zero, the minimum required
+	   buffer length is returned.
+
+     The kdf parameter allows the caller to apply a key derivation function
+     (KDF) on the Diffie-Hellman computation where only the result
+     of the KDF is returned to the caller. The KDF is characterized with
+     struct keyctl_kdf_params as follows:
+
+	 - char *hashname specifies the NUL terminated string identifying
+	   the hash used from the kernel crypto API and applied for the KDF
+	   operation. The KDF implemenation complies with SP800-56A as well
+	   as with SP800-108 (the counter KDF).
+
+	 - char *otherinfo specifies the OtherInfo data as documented in
+	   SP800-56A section 5.8.1.2. The length of the buffer is given with
+	   otherinfolen. The format of OtherInfo is defined by the caller.
+	   The otherinfo pointer may be NULL if no OtherInfo shall be used.
 
      This function will return error EOPNOTSUPP if the key type is not
      supported, error ENOKEY if the key could not be found, or error
-     EACCES if the key is not readable by the caller.
+     EACCES if the key is not readable by the caller. In addition, the
+     function will return EMSGSIZE when the parameter kdf is non-NULL
+     and either the buffer length or the OtherInfo length exceeds the
+     allowed length.
 
 ===============
 KERNEL SERVICES
diff --git a/include/linux/compat.h b/include/linux/compat.h
index f964ef7..f6979d5 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -295,6 +295,13 @@ struct compat_old_sigaction {
 };
 #endif
 
+struct compat_keyctl_kdf_params {
+	compat_uptr_t hashname;
+	compat_uptr_t otherinfo;
+	__u32 otherinfolen;
+	__u32 __spare[8];
+};
+
 struct compat_statfs;
 struct compat_statfs64;
 struct compat_old_linux_dirent;
diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 86eddd6..2102822 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -68,4 +68,11 @@ struct keyctl_dh_params {
 	__s32 base;
 };
 
+struct keyctl_kdf_params {
+	char *hashname;
+	char *otherinfo;
+	__u32 otherinfolen;
+	__u32 __spare[8];
+};
+
 #endif /*  _LINUX_KEYCTL_H */
diff --git a/security/keys/Kconfig b/security/keys/Kconfig
index f826e87..00723a8 100644
--- a/security/keys/Kconfig
+++ b/security/keys/Kconfig
@@ -90,6 +90,7 @@ config KEY_DH_OPERATIONS
        bool "Diffie-Hellman operations on retained keys"
        depends on KEYS
        select MPILIB
+       select CRYPTO_HASH
        help
 	 This option provides support for calculating Diffie-Hellman
 	 public keys and shared secrets using values stored as keys
diff --git a/security/keys/Makefile b/security/keys/Makefile
index 1fd4a16..57dff0c 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -15,7 +15,8 @@ obj-y := \
 	request_key.o \
 	request_key_auth.o \
 	user_defined.o
-obj-$(CONFIG_KEYS_COMPAT) += compat.o
+compat-obj-$(CONFIG_KEY_DH_OPERATIONS) += compat_dh.o
+obj-$(CONFIG_KEYS_COMPAT) += compat.o $(compat-obj-y)
 obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_SYSCTL) += sysctl.o
 obj-$(CONFIG_PERSISTENT_KEYRINGS) += persistent.o
diff --git a/security/keys/compat.c b/security/keys/compat.c
index 36c80bf..b674886 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -133,8 +133,9 @@ COMPAT_SYSCALL_DEFINE5(keyctl, u32, option,
 		return keyctl_get_persistent(arg2, arg3);
 
 	case KEYCTL_DH_COMPUTE:
-		return keyctl_dh_compute(compat_ptr(arg2), compat_ptr(arg3),
-					 arg4, compat_ptr(arg5));
+		return compat_keyctl_dh_compute(compat_ptr(arg2),
+						compat_ptr(arg3),
+						arg4, compat_ptr(arg5));
 
 	default:
 		return -EOPNOTSUPP;
diff --git a/security/keys/compat_dh.c b/security/keys/compat_dh.c
new file mode 100644
index 0000000..a6a659b
--- /dev/null
+++ b/security/keys/compat_dh.c
@@ -0,0 +1,38 @@
+/* 32-bit compatibility syscall for 64-bit systems for DH operations
+ *
+ * Copyright (C) 2016 Stephan Mueller <smueller@chronox.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/uaccess.h>
+
+#include "internal.h"
+
+/*
+ * Perform the DH computation or DH based key derivation.
+ *
+ * If successful, 0 will be returned.
+ */
+long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params,
+			      char __user *buffer, size_t buflen,
+			      struct compat_keyctl_kdf_params __user *kdf)
+{
+	struct keyctl_kdf_params kdfcopy;
+	struct compat_keyctl_kdf_params compat_kdfcopy;
+
+	if (!kdf)
+		return __keyctl_dh_compute(params, buffer, buflen, NULL);
+
+	if (copy_from_user(&compat_kdfcopy, kdf, sizeof(compat_kdfcopy)) != 0)
+		return -EFAULT;
+
+	kdfcopy.hashname = compat_ptr(compat_kdfcopy.hashname);
+	kdfcopy.otherinfo = compat_ptr(compat_kdfcopy.otherinfo);
+	kdfcopy.otherinfolen = compat_kdfcopy.otherinfolen;
+
+	return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
+}
diff --git a/security/keys/dh.c b/security/keys/dh.c
index 531ed2e..51ca787 100644
--- a/security/keys/dh.c
+++ b/security/keys/dh.c
@@ -12,6 +12,10 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <keys/user-type.h>
+
+#include <linux/crypto.h>
+#include <crypto/hash.h>
+
 #include "internal.h"
 
 /*
@@ -77,9 +81,146 @@ error:
 	return ret;
 }
 
-long keyctl_dh_compute(struct keyctl_dh_params __user *params,
-		       char __user *buffer, size_t buflen,
-		       void __user *reserved)
+struct kdf_sdesc {
+	struct shash_desc shash;
+	char ctx[];
+};
+
+static int kdf_alloc(struct kdf_sdesc **sdesc_ret, char *hashname)
+{
+	struct crypto_shash *tfm;
+	struct kdf_sdesc *sdesc;
+	int size;
+
+	/* allocate synchronous hash */
+	tfm = crypto_alloc_shash(hashname, 0, 0);
+	if (IS_ERR(tfm)) {
+		pr_info("could not allocate digest TFM handle %s\n", hashname);
+		return PTR_ERR(tfm);
+	}
+
+	size = sizeof(struct shash_desc) + crypto_shash_descsize(tfm);
+	sdesc = kmalloc(size, GFP_KERNEL);
+	if (!sdesc)
+		return -ENOMEM;
+	sdesc->shash.tfm = tfm;
+	sdesc->shash.flags = 0x0;
+
+	*sdesc_ret = sdesc;
+
+	return 0;
+}
+
+static void kdf_dealloc(struct kdf_sdesc *sdesc)
+{
+	if (!sdesc)
+		return;
+
+	if (sdesc->shash.tfm)
+		crypto_free_shash(sdesc->shash.tfm);
+
+	kzfree(sdesc);
+}
+
+/* convert 32 bit integer into its string representation */
+static inline void crypto_kw_cpu_to_be32(u32 val, u8 *buf)
+{
+	__be32 *a = (__be32 *)buf;
+
+	*a = cpu_to_be32(val);
+}
+
+/*
+ * 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-56A:
+ * 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 kdf_ctr(struct kdf_sdesc *sdesc, const u8 *src, unsigned int slen,
+		   u8 *dst, unsigned int dlen)
+{
+	struct shash_desc *desc = &sdesc->shash;
+	unsigned int h = crypto_shash_digestsize(desc->tfm);
+	int err = 0;
+	u8 *dst_orig = dst;
+	u32 i = 1;
+	u8 iteration[sizeof(u32)];
+
+	while (dlen) {
+		err = crypto_shash_init(desc);
+		if (err)
+			goto err;
+
+		crypto_kw_cpu_to_be32(i, iteration);
+		err = crypto_shash_update(desc, iteration, sizeof(u32));
+		if (err)
+			goto err;
+
+		if (src && slen) {
+			err = crypto_shash_update(desc, src, slen);
+			if (err)
+				goto err;
+		}
+
+		if (dlen < h) {
+			u8 tmpbuffer[h];
+
+			err = crypto_shash_final(desc, tmpbuffer);
+			if (err)
+				goto err;
+			memcpy(dst, tmpbuffer, dlen);
+			memzero_explicit(tmpbuffer, h);
+			return 0;
+		} else {
+			err = crypto_shash_final(desc, dst);
+			if (err)
+				goto err;
+
+			dlen -= h;
+			dst += h;
+			i++;
+		}
+	}
+
+	return 0;
+
+err:
+	memzero_explicit(dst_orig, dlen);
+	return err;
+}
+
+static int keyctl_dh_compute_kdf(struct kdf_sdesc *sdesc,
+				 char __user *buffer, size_t buflen,
+				 uint8_t *kbuf, size_t kbuflen)
+{
+	uint8_t *outbuf = NULL;
+	int ret;
+
+	outbuf = kmalloc(buflen, GFP_KERNEL);
+	if (!outbuf) {
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	ret = kdf_ctr(sdesc, kbuf, kbuflen, outbuf, buflen);
+	if (ret)
+		goto err;
+
+	ret = buflen;
+	if (copy_to_user(buffer, outbuf, buflen) != 0)
+		ret = -EFAULT;
+
+err:
+	kzfree(outbuf);
+	return ret;
+}
+
+long __keyctl_dh_compute(struct keyctl_dh_params __user *params,
+			 char __user *buffer, size_t buflen,
+			 struct keyctl_kdf_params *kdfcopy)
 {
 	long ret;
 	MPI base, private, prime, result;
@@ -88,6 +229,7 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
 	uint8_t *kbuf;
 	ssize_t keylen;
 	size_t resultlen;
+	struct kdf_sdesc *sdesc = NULL;
 
 	if (!params || (!buffer && buflen)) {
 		ret = -EINVAL;
@@ -98,12 +240,34 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
 		goto out;
 	}
 
-	if (reserved) {
-		ret = -EINVAL;
-		goto out;
+	if (kdfcopy) {
+		char *hashname;
+
+		if (buflen > KEYCTL_KDF_MAX_OUTPUT_LEN ||
+		    kdfcopy->otherinfolen > KEYCTL_KDF_MAX_OI_LEN) {
+			ret = -EMSGSIZE;
+			goto out;
+		}
+
+		/* get KDF name string */
+		hashname = strndup_user(kdfcopy->hashname, CRYPTO_MAX_ALG_NAME);
+		if (IS_ERR(hashname)) {
+			ret = PTR_ERR(hashname);
+			goto out;
+		}
+
+		/* allocate KDF from the kernel crypto API */
+		ret = kdf_alloc(&sdesc, hashname);
+		kfree(hashname);
+		if (ret)
+			goto out;
 	}
 
-	keylen = mpi_from_key(pcopy.prime, buflen, &prime);
+	/*
+	 * If the caller requests postprocessing with a KDF, allow an
+	 * arbitrary output buffer size since the KDF ensures proper truncation.
+	 */
+	keylen = mpi_from_key(pcopy.prime, kdfcopy ? SIZE_MAX : buflen, &prime);
 	if (keylen < 0 || !prime) {
 		/* buflen == 0 may be used to query the required buffer size,
 		 * which is the prime key length.
@@ -133,12 +297,25 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
 		goto error3;
 	}
 
-	kbuf = kmalloc(resultlen, GFP_KERNEL);
+	/* allocate space for DH shared secret and SP800-56A otherinfo */
+	kbuf = kmalloc(kdfcopy ? (resultlen + kdfcopy->otherinfolen) : resultlen,
+		       GFP_KERNEL);
 	if (!kbuf) {
 		ret = -ENOMEM;
 		goto error4;
 	}
 
+	/*
+	 * Concatenate SP800-56A otherinfo past DH shared secret -- the
+	 * input to the KDF is (DH shared secret || otherinfo)
+	 */
+	if (kdfcopy && kdfcopy->otherinfo &&
+	    copy_from_user(kbuf + resultlen, kdfcopy->otherinfo,
+			   kdfcopy->otherinfolen) != 0) {
+		ret = -EFAULT;
+		goto error5;
+	}
+
 	ret = do_dh(result, base, private, prime);
 	if (ret)
 		goto error5;
@@ -147,12 +324,17 @@ long keyctl_dh_compute(struct keyctl_dh_params __user *params,
 	if (ret != 0)
 		goto error5;
 
-	ret = nbytes;
-	if (copy_to_user(buffer, kbuf, nbytes) != 0)
-		ret = -EFAULT;
+	if (kdfcopy) {
+		ret = keyctl_dh_compute_kdf(sdesc, buffer, buflen, kbuf,
+					    resultlen + kdfcopy->otherinfolen);
+	} else {
+		ret = nbytes;
+		if (copy_to_user(buffer, kbuf, nbytes) != 0)
+			ret = -EFAULT;
+	}
 
 error5:
-	kfree(kbuf);
+	kzfree(kbuf);
 error4:
 	mpi_free(result);
 error3:
@@ -162,5 +344,21 @@ error2:
 error1:
 	mpi_free(prime);
 out:
+	kdf_dealloc(sdesc);
 	return ret;
 }
+
+long keyctl_dh_compute(struct keyctl_dh_params __user *params,
+		       char __user *buffer, size_t buflen,
+		       struct keyctl_kdf_params __user *kdf)
+{
+	struct keyctl_kdf_params kdfcopy;
+
+	if (!kdf)
+		return __keyctl_dh_compute(params, buffer, buflen, NULL);
+
+	if (copy_from_user(&kdfcopy, kdf, sizeof(kdfcopy)) != 0)
+		return -EFAULT;
+
+	return __keyctl_dh_compute(params, buffer, buflen, &kdfcopy);
+}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index a705a7d..c0f1adf 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -16,6 +16,7 @@
 #include <linux/key-type.h>
 #include <linux/task_work.h>
 #include <linux/keyctl.h>
+#include <linux/compat.h>
 
 struct iovec;
 
@@ -260,15 +261,34 @@ static inline long keyctl_get_persistent(uid_t uid, key_serial_t destring)
 
 #ifdef CONFIG_KEY_DH_OPERATIONS
 extern long keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
-			      size_t, void __user *);
+			      size_t, struct keyctl_kdf_params __user *);
+extern long __keyctl_dh_compute(struct keyctl_dh_params __user *, char __user *,
+				size_t, struct keyctl_kdf_params *);
+#ifdef CONFIG_KEYS_COMPAT
+extern long compat_keyctl_dh_compute(struct keyctl_dh_params __user *params,
+				char __user *buffer, size_t buflen,
+				struct compat_keyctl_kdf_params __user *kdf);
+#endif
+#define KEYCTL_KDF_MAX_OUTPUT_LEN	1024	/* max length of KDF output */
+#define KEYCTL_KDF_MAX_OI_LEN		64	/* max length of otherinfo */
 #else
 static inline long keyctl_dh_compute(struct keyctl_dh_params __user *params,
 				     char __user *buffer, size_t buflen,
-				     void __user *reserved)
+				     struct keyctl_kdf_params __user *kdf)
+{
+	return -EOPNOTSUPP;
+}
+
+#ifdef CONFIG_KEYS_COMPAT
+static inline long compat_keyctl_dh_compute(
+				struct keyctl_dh_params __user *params,
+				char __user *buffer, size_t buflen,
+				struct keyctl_kdf_params __user *kdf)
 {
 	return -EOPNOTSUPP;
 }
 #endif
+#endif
 
 /*
  * Debugging key validation
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index d580ad0..b106898 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1689,7 +1689,7 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
 	case KEYCTL_DH_COMPUTE:
 		return keyctl_dh_compute((struct keyctl_dh_params __user *) arg2,
 					 (char __user *) arg3, (size_t) arg4,
-					 (void __user *) arg5);
+					 (struct keyctl_kdf_params __user *) arg5);
 
 	default:
 		return -EOPNOTSUPP;
-- 
2.7.4

^ permalink raw reply related

* [PATCH v5] DH support: add KDF handling support
From: Stephan Mueller @ 2016-08-19 18:40 UTC (permalink / raw)
  To: mathew.j.martineau, dhowells; +Cc: herbert, linux-crypto, keyrings
In-Reply-To: <1571629.ErTDR5PMQO@positron.chronox.de>

Hi,

this patch changes the documentation, the naming of the variables
and the test case to refer to the variable name of a hashname
instead of kdfname to match the current kernel implementation.

Ciao
Stephan

---8<---

Add the interface logic to support DH with KDF handling support.

The dh_compute code now allows the following options:

- no KDF support / output of raw DH shared secret:
  dh_compute <private> <prime> <base>

- KDF support without "other information" string:
  dh_compute_kdf <private> <prime> <base> <output length> <hash_type>

- KDF support with "other information string:
  dh_compute_kdf_oi <private> <prime> <base> <output length> <hash_type>
  where the OI string is provided on STDIN.

The test to verify the code is based on a test vector used for the CAVS
testing of SP800-56A.

Signed-off-by: Stephan Mueller <smueller@chronox.de>
---
 Makefile                                 |   1 +
 keyctl.c                                 | 133 ++++++++++++++++++++++++
 keyutils.c                               |  14 +++
 keyutils.h                               |  11 ++
 man/keyctl_dh_compute.3                  |  57 +++++++++++
 tests/keyctl/dh_compute/valid/runtest.sh | 168 +++++++++++++++++++++++++++++++
 tests/toolbox.inc.sh                     |  44 ++++++++
 version.lds                              |   2 +
 8 files changed, 430 insertions(+)

diff --git a/Makefile b/Makefile
index 824bbbf..90fc33f 100644
--- a/Makefile
+++ b/Makefile
@@ -195,6 +195,7 @@ endif
 	$(LNS) keyctl_read.3 $(DESTDIR)$(MAN3)/keyctl_read_alloc.3
 	$(LNS) recursive_key_scan.3 $(DESTDIR)$(MAN3)/recursive_session_key_scan.3
 	$(LNS) keyctl_dh_compute.3 $(DESTDIR)$(MAN3)/keyctl_dh_compute_alloc.3
+	$(LNS) keyctl_dh_compute.3 $(DESTDIR)$(MAN3)/keyctl_dh_compute_kdf.3
 	$(INSTALL) -D -m 0644 keyutils.h $(DESTDIR)$(INCLUDEDIR)/keyutils.h
 
 ###############################################################################
diff --git a/keyctl.c b/keyctl.c
index edb03de..de40f5e 100644
--- a/keyctl.c
+++ b/keyctl.c
@@ -20,6 +20,7 @@
 #include <errno.h>
 #include <asm/unistd.h>
 #include "keyutils.h"
+#include <limits.h>
 
 struct command {
 	void (*action)(int argc, char *argv[]) __attribute__((noreturn));
@@ -67,6 +68,8 @@ static nr void act_keyctl_purge(int argc, char *argv[]);
 static nr void act_keyctl_invalidate(int argc, char *argv[]);
 static nr void act_keyctl_get_persistent(int argc, char *argv[]);
 static nr void act_keyctl_dh_compute(int argc, char *argv[]);
+static nr void act_keyctl_dh_compute_kdf(int argc, char *argv[]);
+static nr void act_keyctl_dh_compute_kdf_oi(int argc, char *argv[]);
 
 const struct command commands[] = {
 	{ act_keyctl___version,	"--version",	"" },
@@ -76,6 +79,8 @@ const struct command commands[] = {
 	{ act_keyctl_clear,	"clear",	"<keyring>" },
 	{ act_keyctl_describe,	"describe",	"<keyring>" },
 	{ act_keyctl_dh_compute, "dh_compute",	"<private> <prime> <base>" },
+	{ act_keyctl_dh_compute_kdf, "dh_compute_kdf", "<private> <prime> <base> <len> <hash_name>" },
+	{ act_keyctl_dh_compute_kdf_oi, "dh_compute_kdf_oi", "<private> <prime> <base> <len> <hash_name>" },
 	{ act_keyctl_instantiate, "instantiate","<key> <data> <keyring>" },
 	{ act_keyctl_invalidate,"invalidate",	"<key>" },
 	{ act_keyctl_get_persistent, "get_persistent", "<keyring> [<uid>]" },
@@ -1663,6 +1668,7 @@ static void act_keyctl_dh_compute(int argc, char *argv[])
 		}
 
 		printf("%02hhx", *p);
+		*p = 0x00;	/* zeroize buffer */
 		p++;
 
 		col++;
@@ -1674,6 +1680,133 @@ static void act_keyctl_dh_compute(int argc, char *argv[])
 	} while (--ret > 0);
 
 	printf("\n");
+
+	free(buffer);
+
+	exit(0);
+}
+
+static void act_keyctl_dh_compute_kdf(int argc, char *argv[])
+{
+	key_serial_t private, prime, base;
+	char *buffer;
+	char *p;
+	int ret, sep, col;
+	unsigned long buflen = 0;
+
+	if (argc != 6)
+		format();
+
+	private = get_key_id(argv[1]);
+	prime = get_key_id(argv[2]);
+	base = get_key_id(argv[3]);
+
+	buflen = strtoul(argv[4], NULL, 10);
+	if (buflen == ULONG_MAX)
+		error("dh_compute: cannot convert generated length value");
+
+	buffer = malloc(buflen);
+	if (!buffer)
+		error("dh_compute: cannot allocate memory");
+
+	ret = keyctl_dh_compute_kdf(private, prime, base, argv[5], NULL,  0,
+				    buffer, buflen);
+	if (ret < 0)
+		error("keyctl_dh_compute_alloc");
+
+	/* hexdump the contents */
+	printf("%u bytes of data in result:\n", ret);
+
+	sep = 0;
+	col = 0;
+	p = buffer;
+
+	do {
+		if (sep) {
+			putchar(sep);
+			sep = 0;
+		}
+
+		printf("%02hhx", *p);
+		*p = 0x00;	/* zeroize buffer */
+		p++;
+
+		col++;
+		if (col % 32 == 0)
+			sep = '\n';
+		else if (col % 4 == 0)
+			sep = ' ';
+
+	} while (--ret > 0);
+
+	printf("\n");
+
+	free(buffer);
+
+	exit(0);
+}
+
+static void act_keyctl_dh_compute_kdf_oi(int argc, char *argv[])
+{
+	key_serial_t private, prime, base;
+	char *buffer;
+	char *p;
+	int ret, sep, col;
+	unsigned long buflen = 0;
+	size_t oilen;
+	void *oi;
+
+	if (argc != 6)
+		format();
+
+	private = get_key_id(argv[1]);
+	prime = get_key_id(argv[2]);
+	base = get_key_id(argv[3]);
+
+	buflen = strtoul(argv[4], NULL, 10);
+	if (buflen == ULONG_MAX)
+		error("dh_compute: cannot convert generated length value");
+
+	buffer = malloc(buflen);
+	if (!buffer)
+		error("dh_compute: cannot allocate memory");
+
+	oi = grab_stdin(&oilen);
+
+	ret = keyctl_dh_compute_kdf(private, prime, base, argv[5], oi,  oilen,
+				    buffer, buflen);
+	if (ret < 0)
+		error("keyctl_dh_compute_alloc");
+
+	/* hexdump the contents */
+	printf("%u bytes of data in result:\n", ret);
+
+	sep = 0;
+	col = 0;
+	p = buffer;
+
+	do {
+		if (sep) {
+			putchar(sep);
+			sep = 0;
+		}
+
+		printf("%02hhx", *p);
+		*p = 0x00;	/* zeroize buffer */
+		p++;
+
+		col++;
+		if (col % 32 == 0)
+			sep = '\n';
+		else if (col % 4 == 0)
+			sep = ' ';
+
+	} while (--ret > 0);
+
+	printf("\n");
+
+	free(buffer);
+
 	exit(0);
 }
 
diff --git a/keyutils.c b/keyutils.c
index 2a69304..baff8cb 100644
--- a/keyutils.c
+++ b/keyutils.c
@@ -244,6 +244,20 @@ long keyctl_dh_compute(key_serial_t private, key_serial_t prime,
 	return keyctl(KEYCTL_DH_COMPUTE, &params, buffer, buflen, 0);
 }
 
+long keyctl_dh_compute_kdf(key_serial_t private, key_serial_t prime,
+			   key_serial_t base, char *hashname, char *otherinfo,
+			   size_t otherinfolen, char *buffer, size_t buflen)
+{
+	struct keyctl_dh_params params = { .private = private,
+					   .prime = prime,
+					   .base = base };
+	struct keyctl_kdf_params kdfparams = { .hashname = hashname,
+					       .otherinfo = otherinfo,
+					       .otherinfolen = otherinfolen };
+
+	return keyctl(KEYCTL_DH_COMPUTE, &params, buffer, buflen, &kdfparams);
+}
+
 /*****************************************************************************/
 /*
  * fetch key description into an allocated buffer
diff --git a/keyutils.h b/keyutils.h
index b321aa8..19b66b5 100644
--- a/keyutils.h
+++ b/keyutils.h
@@ -108,6 +108,13 @@ struct keyctl_dh_params {
 	key_serial_t base;
 };
 
+struct keyctl_kdf_params {
+	char *hashname;
+	char *otherinfo;
+	uint32_t otherinfolen;
+	uint32_t __spare[8];
+};
+
 /*
  * syscall wrappers
  */
@@ -163,6 +170,10 @@ extern long keyctl_invalidate(key_serial_t id);
 extern long keyctl_get_persistent(uid_t uid, key_serial_t id);
 extern long keyctl_dh_compute(key_serial_t private, key_serial_t prime,
 			      key_serial_t base, char *buffer, size_t buflen);
+extern long keyctl_dh_compute_kdf(key_serial_t private, key_serial_t prime,
+				  key_serial_t base, char *hashname,
+				  char *otherinfo, size_t otherinfolen,
+				  char *buffer, size_t buflen);
 
 /*
  * utilities
diff --git a/man/keyctl_dh_compute.3 b/man/keyctl_dh_compute.3
index b06d39e..2e5bb0f 100644
--- a/man/keyctl_dh_compute.3
+++ b/man/keyctl_dh_compute.3
@@ -11,6 +11,8 @@
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH NAME
 keyctl_dh_compute \- Compute a Diffie-Hellman shared secret or public key
+.br
+keyctl_dh_compute_kdf \- Derive key from a Diffie-Hellman shared secret
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SYNOPSIS
 .nf
@@ -21,6 +23,10 @@ keyctl_dh_compute \- Compute a Diffie-Hellman shared secret or public key
 .sp
 .BI "long keyctl_dh_compute_alloc(key_serial_t " private,
 .BI "key_serial_t " prime ", key_serial_t " base ", void **" _buffer ");"
+.sp
+.BI "long keyctl_dh_compute_kdf(key_serial_t " private ", key_serial_t " prime ,
+.BI "key_serial_t " base ", char *" hashname ", char *" otherinfo ",
+.BI "size_t " otherinfolen ", char *" buffer ", size_t " buflen ");"
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH DESCRIPTION
 .BR keyctl_dh_compute ()
@@ -64,6 +70,48 @@ places the data in it.  If successful, a pointer to the buffer is placed in
 .IR *_buffer .
 The caller must free the buffer.
 .P
+.BR keyctl_dh_compute_kdf ()
+derives a key from a Diffie-Hellman shared secret according to the protocol
+specified in SP800-56A. The Diffie-Hellman computation is based on the same
+primitives as discussed
+for
+.BR keyctl_dh_compute ().
+.P
+To implement the protocol of SP800-56A
+.I base
+is a key containing the remote public key to compute the Diffie-Hellman
+shared secret. That shared secret is post-processed with a key derivation
+function.
+.P
+The
+.I hashname
+specifies the Linux kernel crypto API name for a hash that shall be used
+for the key derivation function, such as sha256.
+The
+.I hashname
+must be a NULL terminated string.
+.P
+Following the specification of SP800-56A section 5.8.1.2 the
+.I otherinfo
+parameter may be provided. The format of the OtherInfo field is defined
+by the caller. The caller may also specify NULL as a valid argument when
+no OtherInfo data shall be processed. The length of the
+.I otherinfo
+parameter is specified with
+.I otherinfolen
+and is restricted to a maximum length by the kernel.
+.P
+The KDF returns the requested number of bytes specified with the
+.I genlen
+or the
+.I buflen
+parameter depending on the invoked function.
+.P
+.I buffer
+and
+.I buflen
+specify the buffer into which the computed result will be placed.
+.P
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH RETURN VALUE
 On success
@@ -91,6 +139,15 @@ The buffer pointer is invalid or buflen is too small.
 .TP
 .B EOPNOTSUPP
 One of the keys was not a valid user key.
+.TP
+.B EMSGSIZE
+When using
+.BR keyctl_dh_compute_kdf (),
+the size of either
+.I otherinfolen
+or
+.I buflen
+is too big.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH LINKING
 This is a library function that can be found in
diff --git a/tests/keyctl/dh_compute/valid/runtest.sh b/tests/keyctl/dh_compute/valid/runtest.sh
index f2aace6..6498eef 100644
--- a/tests/keyctl/dh_compute/valid/runtest.sh
+++ b/tests/keyctl/dh_compute/valid/runtest.sh
@@ -84,5 +84,173 @@ expect_multiline payload "$public"
 
 echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
 
+
+################################################################
+# Testing DH compute with KDF according to SP800-56A
+#
+# test vectors from http://csrc.nist.gov/groups/STM/cavp/documents/keymgmt/KASTestVectorsFFC2014.zip
+################################################################
+
+# SHA-256
+
+# XephemCAVS
+private="\x81\xb2\xc6\x5f\x5c\xba\xc0\x0b\x13\x53\xac\x38\xbd\x77\xa2\x5a"
+private+="\x86\x50\xed\x48\x5e\x41\x3e\xac\x1d\x6c\x48\x85"
+
+# P
+prime="\xa3\xcc\x62\x23\xe5\x0c\x6e\x3f\x7b\xb0\x58\x1d\xcb\x9e\x9f\xf0"
+prime+="\x2c\x58\x07\x68\x32\x8a\x15\x20\x7b\x1c\x32\x31\x7f\xb7\x84\x96"
+prime+="\x81\x5e\x3c\xf7\xf9\xd0\x9c\xcb\x9f\xa8\x40\xff\x47\x98\x51\x1a"
+prime+="\x17\xb5\x59\x28\x72\x1e\x5d\xfb\xcc\xc5\x41\x47\xe0\xf0\x5f\x85"
+prime+="\xb3\xac\x41\x0b\x6a\xe3\xf5\x9b\x79\x6f\x3f\xea\xc7\xfc\x52\x49"
+prime+="\x21\x7e\xb2\xa0\x45\x88\x29\x3a\x5a\xde\x22\x78\x79\xf4\x6c\xeb"
+prime+="\x56\x45\x7b\x5c\x43\x12\x93\xe5\xe1\x04\xd1\xb9\x64\xbd\x2c\xdf"
+prime+="\xde\xff\xa0\x40\x49\xa9\x1e\x67\xee\x8c\x86\xe9\x44\xf0\x4f\x94"
+prime+="\x4a\x30\xe3\x61\xf8\xd1\x5d\x17\xe5\x01\x0c\xab\xb4\xef\x40\xc0"
+prime+="\xeb\xa5\xf4\xa2\x52\xd4\xfd\x6c\xf9\xda\xe6\x0e\x86\xe4\xb3\x00"
+prime+="\x9b\x1d\xfc\x92\x66\x70\x35\x72\x61\x58\x7a\xd0\x5c\x00\xa6\xc6"
+prime+="\xf0\x10\x6c\xec\x8f\xc5\x91\x31\x51\x50\x84\xa8\x70\x59\x41\x65"
+prime+="\xb4\x93\x90\xdb\x2d\x00\xe7\x53\x8f\x23\x0d\x53\x2f\x4a\x4e\xca"
+prime+="\x83\x09\xd7\x07\xc0\xb3\x83\x5c\xee\x04\xf3\xca\x55\x8a\x22\xc6"
+prime+="\xb5\x20\xfe\x25\xde\x6f\xfa\x90\xef\xda\x49\x27\xd0\x18\x59\x4c"
+prime+="\x0c\x0b\x77\x06\x73\x93\xb7\xf1\xe0\xfc\x7c\xf2\x16\xaf\xf3\x9f"
+
+# YephemIUT
+xa="\x9a\x70\x82\x2d\x3f\x06\x12\x3d\x0e\x51\x8e\xe1\x16\x51\xe5\xf6"
+xa+="\xb1\x19\xdc\x3b\x97\xd5\xb1\xc0\xa2\xa6\xf6\xde\x94\x25\x64\xba"
+xa+="\x10\x06\x1e\xec\xde\xb7\x36\x9c\xa5\x37\x49\x9e\x04\xb0\x36\xe9"
+xa+="\x7f\x44\x5a\x95\x6f\x63\x69\xae\x6e\x63\xfd\x27\xea\xe3\xe3\x47"
+xa+="\x85\x54\x47\xd3\xba\xc1\xc6\x0c\x10\xe7\x35\x07\x72\xc6\xc0\xc6"
+xa+="\xfb\xf9\xca\x3e\x38\xf0\xe8\x65\x88\x25\xd3\xb2\x0f\x1f\x02\x8f"
+xa+="\x35\xe3\x4d\x12\x35\x10\x3d\xf2\x33\x9b\x5b\x09\x9d\x3f\xe3\xe5"
+xa+="\x34\x6a\x69\x16\x42\xba\xc5\xb0\xbb\x03\xcd\x5d\x04\xd7\x56\x26"
+xa+="\x21\x49\x3f\xf1\xc4\x27\x3b\x6a\x45\xc5\xec\xb0\xb5\xe9\x08\xa0"
+xa+="\xf9\xf5\x62\x28\x2e\x85\x3e\xfc\x9a\x7e\xa1\x12\xe9\x47\x4f\xf6"
+xa+="\x94\x18\xf7\xc4\x7a\xe9\x66\xd4\x52\x4c\xa1\x70\x1b\x60\xa4\xbe"
+xa+="\x15\xc7\x5e\x27\xb4\x05\x80\x64\x68\x15\x6e\x02\xcb\xc5\x8f\xf4"
+xa+="\x66\x3c\x96\xac\x0c\x87\x36\x81\x35\xfa\x9b\x0b\xb6\x33\x7a\xe2"
+xa+="\x58\x52\x1d\x7d\x60\xc2\xa9\x1b\x4e\xd7\x72\xad\x65\x03\x40\x49"
+xa+="\x97\xf6\x79\x9d\xf6\x63\xa8\x99\x9c\xfd\x74\x7f\xa0\x67\xb9\x05"
+xa+="\x8a\xb3\x3b\xc1\x45\x94\x36\x6f\x28\xf5\xa2\xd9\x00\xb6\x46\x7a"
+
+# Z
+read -d '' shared <<"EOF"
+0fdbd9a2 ebf50cba 489b4e4d 7cd6924a 42ee6324 a26988b2 22bc38e6 9cc445f1
+eb47c1a4 62eca39f 39bcd7b8 19dede51 30bc38da ec99c16f 40a4e5c1 9c97b796
+8b41823d a0650e37 13c73e6f 5f2a9dff 2e67dbf5 40ee66f4 e694c28f ba1d604b
+71b57b8a eeb67a35 ba425a38 490b6fb9 f713db22 6f893b7a 8962f426 ba3046fb
+cff8538c 16f583e8 ae947672 0ba55ff9 75b440d0 c4565cc7 5837d23a fea61a39
+e0b7f6c4 e24c2154 7eb19fce f8dbed10 b06a9cce 971c0f0f ba7c1d5c b5035eaa
+4fddd3ba fe757339 e3321e3e 4ebfe9e7 9c6c0401 4df63cf9 28d0a2c0 5b2d5521
+030c35f1 c84c97fe 64cad509 8012a003 d52d24c4 1a1f9348 b7575251 3facb02f
+EOF
+
+# OI
+otherinfo="\xa1\xb2\xc3\xd4\xe5\x43\x41\x56\x53\x69\x64\x0d\x64\xc1\xb2"
+otherinfo+="\x33\x61\xb2\x61\xde\x78\x68\x8e\xa8\x65\xfc\xff\x11\x3c\x84"
+
+# DKM
+read -d '' derived <<"EOF"
+8284e313 02c8a26b 393ec52d 9f9e0882
+EOF
+
+pcreate_key "-e $prime" user dh:prime @s
+expect_keyid primeid
+
+pcreate_key "-e $xa" user dh:xa @s
+expect_keyid xaid
+
+pcreate_key "-e $private" user dh:private @s
+expect_keyid privateid
+
+marker "COMPUTE DH SHARED SECRET"
+dh_compute $privateid $primeid $xaid
+expect_multiline payload "$shared"
+
+marker "COMPUTE DERIVED KEY FROM DH SHARED SECRET (SHA-256)"
+echo -e -n $otherinfo | dh_compute_kdf_oi $privateid $primeid $xaid 16 "sha256"
+expect_multiline payload "$derived"
+
+
+# SHA-224
+
+# XephemCAVS
+private="\x86\x1b\xa2\x59\xab\xa6\xaa\x57\x7d\xe2\x2f\x50\x8e\xcb\xbc\x26"
+private+="\xc5\xac\xfc\xcb\x9e\xa2\x3b\x43\x4d\x6d\x2b\x79"
+
+# P
+prime="\xa5\xb1\x76\x4e\x13\xc8\x16\x99\xab\xa3\x8f\x0d\xc0\xd1\x5e\x15"
+prime+="\xf5\x0f\xcd\x5c\xf7\xc2\x23\x72\xca\xfc\x5e\xd7\x62\x94\x1b\xd9"
+prime+="\xe0\xfb\x9a\xab\xee\x74\x66\xd2\xc8\x29\xaa\xb0\x31\xdb\x7b\x1b"
+prime+="\x5a\x64\xe6\x8e\xd5\x3b\xaf\xb2\x83\xba\x0f\x01\x8b\xeb\x3e\xdc"
+prime+="\x95\x7f\xe4\x53\xbe\x0d\xaa\xb6\x1b\x32\x28\x76\x3e\x80\x75\x8c"
+prime+="\x6d\x8c\x28\x3c\xf6\x30\xed\xd9\xd7\x0a\x8a\xf3\x30\xdd\x0a\xf6"
+prime+="\xa8\xd5\x94\xc2\x3c\xdd\x24\xc8\xad\x3f\xcf\xea\x41\x75\x77\x72"
+prime+="\xce\xed\x92\x1e\x63\x86\x2f\x24\x6e\x6f\x49\xd8\x74\x7e\x44\xae"
+prime+="\xf0\x1e\x30\x9b\x6d\xcc\x80\xd4\x50\x38\x3b\xb1\xf9\x4d\xd5\x90"
+prime+="\x84\xf8\xe9\x6f\x85\x6e\xc7\xc8\x33\x5e\xdb\x05\x5f\x8e\xc6\xc4"
+prime+="\x81\x52\x0b\x3f\x28\xe8\x0b\x62\x09\xb8\xae\x61\xcc\x86\x0e\x24"
+prime+="\xc8\x22\xb6\x6c\x4f\x97\x80\x49\x93\xbc\xd0\xa9\x72\xb3\x53\x54"
+prime+="\x01\x33\x0e\xbe\x4b\x2e\x92\x3f\x18\x9b\x63\x35\x62\xe4\x68\xeb"
+prime+="\x99\xa4\xbc\x88\xcc\xbf\xf8\xdf\x0f\xd5\xaf\xcf\xe6\xae\x19\x18"
+prime+="\x42\x14\xab\x3f\xef\xb7\xf0\x66\x8b\x8b\x26\x83\xbe\xbd\x56\x51"
+prime+="\xa4\xc6\x38\x43\xb9\xb1\x4b\xc7\x38\xd5\x20\xb1\xb7\x21\x2c\x69"
+
+# YephemIUT
+xa="\x17\xd7\x1a\xf4\x35\x3c\x22\x12\x2a\xeb\x2a\x06\x19\xcc\x2c\xf7"
+xa+="\x35\x53\xf2\x8e\x9f\xb1\x91\xfd\xb2\x86\xb1\x15\xb9\xfd\xa8\x66"
+xa+="\x2d\xe5\x17\x3b\x1a\xff\x70\x48\x8d\x9b\xc8\x48\xe5\x37\xd7\xe5"
+xa+="\x02\x16\x49\xd3\x7d\xc7\x8c\x94\x36\x9d\xb9\x0c\x27\x84\xc9\x4d"
+xa+="\x97\x0a\xc9\xb5\xe3\x5e\xfd\x22\xd4\x18\xd3\x1b\x68\xd9\x55\x0b"
+xa+="\xaa\x77\x16\xe9\x8e\xa6\x78\x3b\xb3\xa8\x45\x05\x9f\xba\xa4\xa6"
+xa+="\x72\x0a\x6a\x23\xc5\x6b\xa5\x2b\x4d\x9b\x72\x6e\x00\x68\xe9\xeb"
+xa+="\x4d\x17\x5b\xff\x43\x69\xf3\xd2\xa4\xaf\x66\xee\xcd\x62\xef\x7b"
+xa+="\x23\xc3\x37\xd4\x70\x95\x2b\x17\x67\xc8\xbf\x78\x2f\x0b\x58\xb4"
+xa+="\xfc\x82\x45\xf8\x40\x78\x71\x70\xf4\xb0\xa5\x1b\x5e\xb4\x60\x75"
+xa+="\x8a\xdd\xc9\xf4\x4a\x73\xa3\xf6\x07\x60\x3b\xd3\x50\x73\xd1\xa6"
+xa+="\x9a\x20\x3a\x04\x94\xa8\xc2\x02\x1b\xa0\xda\x1f\x04\x95\xf5\x60"
+xa+="\xc0\xba\x81\x79\x4e\xee\xeb\x82\x5d\x1b\xd3\x43\x16\xa5\x2a\xe1"
+xa+="\xc9\x00\x10\x0c\x0d\x6f\xa0\x25\x46\xed\x7a\x9c\x38\xa6\xa3\x43"
+xa+="\xd6\x86\x59\xee\xb5\x9c\xf3\x81\x04\xa9\x6b\xb2\x5a\x6d\xbb\xf0"
+xa+="\xcb\xc0\xed\xe7\x3a\x7b\xba\x67\x51\x81\xe0\xcd\x2e\x7b\x9f\x89"
+
+# Z
+read -d '' shared <<"EOF"
+057c22b8 c5872fef 08ebe852 fafab4b7 c2c2ffbb 376d71bd a941b16e 32614adf
+ebb82aeb d50f29d3 cec63d10 77f50e21 cf381b87 a818c614 52c5cce2 af85f40c
+06615b97 fe8c3a80 68990ac5 83957b52 8dd6d52d a3b51e84 aec355fd 4a3fe5ce
+faa3b17c 9e71cb4d 28ecab6d 21297280 e52397b7 ccb1b62d 8d5d3ce4 1d26b2a3
+bdbf880b b39e8b02 8a745ff2 9f0984da efe97084 5d850884 525403ca d2a52956
+f55b9a89 b2d801f1 710333c0 479c5955 b54c8163 83c65ad9 c78b8c67 cc1b211b
+208b9fab b9c99a68 18293e6a 8da069e6 75eb4317 668a7d4b 6f235533 f3ff4ed0
+4f8ad579 f9ad14e7 f68ae183 41d603d9 d6297123 00716c98 bbbf16eb 2a2cc92f
+EOF
+
+# OI
+otherinfo="\xa1\xb2\xc3\xd4\xe5\x43\x41\x56\x53\x69\x64\xaa\x27\xe2\x49"
+otherinfo+="\xbf\x0a\x12\x76\x46\x8d\x80\x82\x59\xf3\xb8\xe2\x68\x78\x51"
+
+# DKM
+read -d '' derived <<"EOF"
+88bf39c0 08eec33a dc3b4430 054ba262
+EOF
+
+pcreate_key "-e $prime" user dh:prime @s
+expect_keyid primeid
+
+pcreate_key "-e $xa" user dh:xa @s
+expect_keyid xaid
+
+pcreate_key "-e $private" user dh:private @s
+expect_keyid privateid
+
+marker "COMPUTE DH SHARED SECRET"
+dh_compute $privateid $primeid $xaid
+expect_multiline payload "$shared"
+
+marker "COMPUTE DERIVED KEY FROM DH SHARED SECRET (SHA-224)"
+echo -e -n $otherinfo | dh_compute_kdf_oi $privateid $primeid $xaid 16 "sha224"
+expect_multiline payload "$derived"
+
 # --- then report the results in the database ---
 toolbox_report_result $TEST $result
diff --git a/tests/toolbox.inc.sh b/tests/toolbox.inc.sh
index 7f19a02..27b253f 100644
--- a/tests/toolbox.inc.sh
+++ b/tests/toolbox.inc.sh
@@ -1106,6 +1106,50 @@ function dh_compute ()
 
 ###############################################################################
 #
+# Do a DH computation post-processed by a KDF
+#
+###############################################################################
+function dh_compute_kdf ()
+{
+    my_exitval=0
+    if [ "x$1" = "x--fail" ]
+    then
+	my_exitval=1
+	shift
+    fi
+
+    echo keyctl dh_compute_kdf $@ >>$OUTPUTFILE
+    keyctl dh_compute_kdf $@ >>$OUTPUTFILE 2>&1
+    if [ $? != $my_exitval ]
+    then
+	failed
+    fi
+}
+
+###############################################################################
+#
+# Do a DH computation post-processed by a KDF with other information
+#
+###############################################################################
+function dh_compute_kdf_oi ()
+{
+    my_exitval=0
+    if [ "x$1" = "x--fail" ]
+    then
+	my_exitval=1
+	shift
+    fi
+
+    echo keyctl dh_compute_kdf_oi $@ >>$OUTPUTFILE
+    keyctl dh_compute_kdf_oi $@ >>$OUTPUTFILE 2>&1
+    if [ $? != $my_exitval ]
+    then
+	failed
+    fi
+}
+
+###############################################################################
+#
 # Make sure we sleep at least N seconds
 #
 ###############################################################################
diff --git a/version.lds b/version.lds
index 2bfed13..b8eebfb 100644
--- a/version.lds
+++ b/version.lds
@@ -66,5 +66,7 @@ KEYUTILS_1.6 {
 	/* management functions */
 	keyctl_dh_compute;
 	keyctl_dh_compute_alloc;
+	keyctl_dh_compute_kdf;
+	keyctl_dh_compute_kdf_alloc;
 
 } KEYUTILS_1.5;
-- 
2.7.4

^ permalink raw reply related

* Re: [PATCH v6 0/5] /dev/random - a new approach
From: H. Peter Anvin @ 2016-08-19 17:20 UTC (permalink / raw)
  To: Herbert Xu, Theodore Ts'o, Pavel Machek, Stephan Mueller,
	sandyinchina, Jason Cooper, John Denker, Joe Perches,
	George Spelvin, linux-crypto, linux-kernel
In-Reply-To: <20160819055612.GA20427@gondor.apana.org.au>

On 08/18/16 22:56, Herbert Xu wrote:
> On Thu, Aug 18, 2016 at 10:49:47PM -0400, Theodore Ts'o wrote:
>>
>> That really depends on the system.  We can't assume that people are
>> using systems with a 100Hz clock interrupt.  More often than not
>> people are using tickless kernels these days.  That's actually the
>> problem with changing /dev/urandom to block until things are
>> initialized.
> 
> Couldn't we disable tickless until urandom has been seeded? In fact
> perhaps we should accelerate the timer interrupt rate until it has
> been seeded?
> 

The biggest problem there is that the timer interrupt adds *no* entropy
unless there is a source of asynchronicity in the system.  On PCs,
traditionally the timer has been run from a completely different crystal
(14.31818 MHz) than the CPU, which is the ideal situation, but if they
are run off the same crystal and run in lockstep, there is very little
if anything there.  On some systems, the timer may even *be* the only
source of time, and the entropy truly is zero.

	-hpa

^ permalink raw reply

* [PATCH 2/5] hwrng: amd: use the BIT macro
From: LABBE Corentin @ 2016-08-19 13:42 UTC (permalink / raw)
  To: herbert, mpm; +Cc: linux-crypto, linux-kernel, LABBE Corentin
In-Reply-To: <1471614177-12380-1-git-send-email-clabbe.montjoie@gmail.com>

This patch add usage of the BIT() macro

Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
 drivers/char/hw_random/amd-rng.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 45b7965..d0042f5 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -78,11 +78,11 @@ static int amd_rng_init(struct hwrng *rng)
 	u8 rnen;
 
 	pci_read_config_byte(amd_pdev, 0x40, &rnen);
-	rnen |= (1 << 7);	/* RNG on */
+	rnen |= BIT(7);	/* RNG on */
 	pci_write_config_byte(amd_pdev, 0x40, rnen);
 
 	pci_read_config_byte(amd_pdev, 0x41, &rnen);
-	rnen |= (1 << 7);	/* PMIO enable */
+	rnen |= BIT(7);	/* PMIO enable */
 	pci_write_config_byte(amd_pdev, 0x41, rnen);
 
 	return 0;
@@ -93,7 +93,7 @@ static void amd_rng_cleanup(struct hwrng *rng)
 	u8 rnen;
 
 	pci_read_config_byte(amd_pdev, 0x40, &rnen);
-	rnen &= ~(1 << 7);	/* RNG off */
+	rnen &= ~BIT(7);	/* RNG off */
 	pci_write_config_byte(amd_pdev, 0x40, rnen);
 }
 
-- 
2.7.3

^ permalink raw reply related

* [PATCH 4/5] hwrng: amd: Remove asm/io.h
From: LABBE Corentin @ 2016-08-19 13:42 UTC (permalink / raw)
  To: herbert, mpm; +Cc: linux-crypto, linux-kernel, LABBE Corentin
In-Reply-To: <1471614177-12380-1-git-send-email-clabbe.montjoie@gmail.com>

checkpatch complains about <asm/io.h> used instead of linux/io.h.
In fact it is not needed.
This patch remove it, and in the process, alphabetize the other headers.

Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
 drivers/char/hw_random/amd-rng.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index d0a806a..9ddc99c 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -24,12 +24,11 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/hw_random.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/pci.h>
-#include <linux/hw_random.h>
-#include <linux/delay.h>
-#include <asm/io.h>
 
 #define DRV_NAME "AMD768-HWRNG"
 
-- 
2.7.3

^ permalink raw reply related

* [PATCH 5/5] hwrng: amd: Rework of the amd768-hwrng driver
From: LABBE Corentin @ 2016-08-19 13:42 UTC (permalink / raw)
  To: herbert, mpm; +Cc: linux-crypto, linux-kernel, LABBE Corentin
In-Reply-To: <1471614177-12380-1-git-send-email-clabbe.montjoie@gmail.com>

This patch convert the hwrng interface used by amd768-rng to its new API
by replacing data_read()/data_present() by read().

Furthermore, Instead of having two global variable, it's better to use a
private struct. This will permit to remove amd_pdev variable.

Finally, Instead of accessing hw directly via pmbase, it's better to
access after ioport_map() via ioread32/iowrite32.

Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
 drivers/char/hw_random/amd-rng.c | 151 +++++++++++++++++++++++++--------------
 1 file changed, 99 insertions(+), 52 deletions(-)

diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 9ddc99c..efdd853 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -32,6 +32,14 @@
 
 #define DRV_NAME "AMD768-HWRNG"
 
+#define GEN_CFG_REG1	0x40
+#define GEN_CFG_REG2	0x41
+#define SMIO_SPACEPTR	0x58
+#define RNGDATA		0x00
+#define RNGDONE		0x04
+#define PMBASE_OFFSET	0xF0
+#define PMBASE_SIZE	8
+
 /*
  * Data for PCI driver interface
  *
@@ -39,6 +47,7 @@
  * PCI ids via MODULE_DEVICE_TABLE.  We do not actually
  * register a pci_driver, because someone else might one day
  * want to register another driver on the same PCI id.
+ * Like i2c-amd756
  */
 static const struct pci_device_id pci_tbl[] = {
 	{ PCI_VDEVICE(AMD, 0x7443), 0, },
@@ -47,112 +56,150 @@ static const struct pci_device_id pci_tbl[] = {
 };
 MODULE_DEVICE_TABLE(pci, pci_tbl);
 
-static struct pci_dev *amd_pdev;
+struct amd768_priv {
+	void __iomem *iobase;
+	struct pci_dev *pcidev;
+	u32 pmbase;
+};
 
-static int amd_rng_data_present(struct hwrng *rng, int wait)
+static int amd_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
 {
-	u32 pmbase = (u32)rng->priv;
-	int data, i;
-
-	for (i = 0; i < 20; i++) {
-		data = !!(inl(pmbase + 0xF4) & 1);
-		if (data || !wait)
-			break;
-		udelay(10);
+	u32 *data = buf;
+	struct amd768_priv *priv = (struct amd768_priv *)rng->priv;
+	size_t read = 0;
+	/* We will wait at maximum one time per read */
+	int timeout = max / 4 + 1;
+
+	/*
+	 * RNG data is available when RNGDONE is set to 1
+	 * New random numbers are generated approximately 128 microseconds
+	 * after RNGDATA is read
+	 */
+	while (read < max) {
+		if (ioread32(priv->iobase + RNGDONE) == 0) {
+			if (wait) {
+				/* Delay given by datasheet */
+				usleep_range(128, 196);
+				if (timeout-- == 0)
+					return read;
+			} else {
+				return 0;
+			}
+		} else {
+			*data = ioread32(priv->iobase + RNGDATA);
+			data++;
+			read += 4;
+		}
 	}
-	return data;
-}
-
-static int amd_rng_data_read(struct hwrng *rng, u32 *data)
-{
-	u32 pmbase = (u32)rng->priv;
 
-	*data = inl(pmbase + 0xF0);
-
-	return 4;
+	return read;
 }
 
 static int amd_rng_init(struct hwrng *rng)
 {
 	u8 rnen;
+	struct amd768_priv *priv = (struct amd768_priv *)rng->priv;
 
-	pci_read_config_byte(amd_pdev, 0x40, &rnen);
+	pci_read_config_byte(priv->pcidev, GEN_CFG_REG1, &rnen);
 	rnen |= BIT(7);	/* RNG on */
-	pci_write_config_byte(amd_pdev, 0x40, rnen);
+	pci_write_config_byte(priv->pcidev, GEN_CFG_REG1, rnen);
 
-	pci_read_config_byte(amd_pdev, 0x41, &rnen);
+	pci_read_config_byte(priv->pcidev, GEN_CFG_REG2, &rnen);
 	rnen |= BIT(7);	/* PMIO enable */
-	pci_write_config_byte(amd_pdev, 0x41, rnen);
-
+	pci_write_config_byte(priv->pcidev, GEN_CFG_REG2, rnen);
 	return 0;
 }
 
 static void amd_rng_cleanup(struct hwrng *rng)
 {
 	u8 rnen;
+	struct amd768_priv *priv = (struct amd768_priv *)rng->priv;
 
-	pci_read_config_byte(amd_pdev, 0x40, &rnen);
+	pci_read_config_byte(priv->pcidev, GEN_CFG_REG1, &rnen);
 	rnen &= ~BIT(7);	/* RNG off */
-	pci_write_config_byte(amd_pdev, 0x40, rnen);
+	pci_write_config_byte(priv->pcidev, GEN_CFG_REG1, rnen);
 }
 
 static struct hwrng amd_rng = {
 	.name		= DRV_NAME,
+	.read		= amd_rng_read,
 	.init		= amd_rng_init,
 	.cleanup	= amd_rng_cleanup,
-	.data_present	= amd_rng_data_present,
-	.data_read	= amd_rng_data_read,
 };
 
-static int __init mod_init(void)
+static int mod_init(void)
 {
-	int err = -ENODEV;
+	int err;
 	struct pci_dev *pdev = NULL;
 	const struct pci_device_id *ent;
 	u32 pmbase;
+	struct amd768_priv *priv;
 
 	for_each_pci_dev(pdev) {
 		ent = pci_match_id(pci_tbl, pdev);
 		if (ent)
 			goto found;
 	}
-	/* Device not found. */
-	goto out;
-
+	return -ENODEV;
 found:
-	err = pci_read_config_dword(pdev, 0x58, &pmbase);
+
+	err = pci_read_config_dword(pdev, SMIO_SPACEPTR, &pmbase);
 	if (err)
-		goto out;
-	err = -EIO;
+		return err;
+
 	pmbase &= 0x0000FF00;
-	if (pmbase == 0)
-		goto out;
-	if (!request_region(pmbase + 0xF0, 8, DRV_NAME)) {
-		dev_err(&pdev->dev, DRV_NAME " region 0x%x already in use!\n",
-			pmbase + 0xF0);
-		err = -EBUSY;
-		goto out;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	if (!request_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE, DRV_NAME)) {
+		pr_err(DRV_NAME "region 0x%x already in use!\n", pmbase);
+		goto err_pmbase;
+	}
+
+	priv->iobase = ioport_map(pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+	if (!priv->iobase) {
+		pr_err(DRV_NAME "Cannot map ioport\n");
+		err = -EINVAL;
+		goto err_iomap;
 	}
-	amd_rng.priv = (unsigned long)pmbase;
-	amd_pdev = pdev;
+
+	amd_rng.priv = (unsigned long)priv;
+	priv->pmbase = pmbase;
+	priv->pcidev = pdev;
 
 	pr_info(DRV_NAME " detected\n");
+
 	err = hwrng_register(&amd_rng);
 	if (err) {
-		pr_err(DRV_NAME " registering failed (%d)\n", err);
-		release_region(pmbase + 0xF0, 8);
-		goto out;
+		pr_err(DRV_NAME "Cannot register HWRNG %d\n", err);
+		goto err_hwrng;
 	}
-out:
+	return 0;
+
+err_hwrng:
+	ioport_unmap(priv->iobase);
+err_iomap:
+	release_region(pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+err_pmbase:
+	kfree(priv);
 	return err;
 }
 
-static void __exit mod_exit(void)
+static void mod_exit(void)
 {
-	u32 pmbase = (unsigned long)amd_rng.priv;
+	struct amd768_priv *priv;
+
+	priv = (struct amd768_priv *)amd_rng.priv;
 
-	release_region(pmbase + 0xF0, 8);
 	hwrng_unregister(&amd_rng);
+
+	ioport_unmap(priv->iobase);
+
+	release_region(priv->pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+
+	kfree(priv);
 }
 
 module_init(mod_init);
-- 
2.7.3

^ permalink raw reply related

* [PATCH 3/5] hwrng: amd: Be consitent with the driver name
From: LABBE Corentin @ 2016-08-19 13:42 UTC (permalink / raw)
  To: herbert, mpm; +Cc: linux-crypto, linux-kernel, LABBE Corentin
In-Reply-To: <1471614177-12380-1-git-send-email-clabbe.montjoie@gmail.com>

The driver name is displayed each time differently.
This patch make use of the same name everywhere.

Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
 drivers/char/hw_random/amd-rng.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index d0042f5..d0a806a 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -31,7 +31,7 @@
 #include <linux/delay.h>
 #include <asm/io.h>
 
-#define PFX	KBUILD_MODNAME ": "
+#define DRV_NAME "AMD768-HWRNG"
 
 /*
  * Data for PCI driver interface
@@ -98,7 +98,7 @@ static void amd_rng_cleanup(struct hwrng *rng)
 }
 
 static struct hwrng amd_rng = {
-	.name		= "amd",
+	.name		= DRV_NAME,
 	.init		= amd_rng_init,
 	.cleanup	= amd_rng_cleanup,
 	.data_present	= amd_rng_data_present,
@@ -128,8 +128,8 @@ found:
 	pmbase &= 0x0000FF00;
 	if (pmbase == 0)
 		goto out;
-	if (!request_region(pmbase + 0xF0, 8, "AMD HWRNG")) {
-		dev_err(&pdev->dev, "AMD HWRNG region 0x%x already in use!\n",
+	if (!request_region(pmbase + 0xF0, 8, DRV_NAME)) {
+		dev_err(&pdev->dev, DRV_NAME " region 0x%x already in use!\n",
 			pmbase + 0xF0);
 		err = -EBUSY;
 		goto out;
@@ -137,11 +137,10 @@ found:
 	amd_rng.priv = (unsigned long)pmbase;
 	amd_pdev = pdev;
 
-	pr_info("AMD768 RNG detected\n");
+	pr_info(DRV_NAME " detected\n");
 	err = hwrng_register(&amd_rng);
 	if (err) {
-		pr_err(PFX "RNG registering failed (%d)\n",
-		       err);
+		pr_err(DRV_NAME " registering failed (%d)\n", err);
 		release_region(pmbase + 0xF0, 8);
 		goto out;
 	}
-- 
2.7.3

^ permalink raw reply related

* [PATCH 1/5] hwrng: amd: Fix style problem with blank line
From: LABBE Corentin @ 2016-08-19 13:42 UTC (permalink / raw)
  To: herbert, mpm; +Cc: linux-crypto, linux-kernel, LABBE Corentin

Some blank line are unncessary, and one is missing after declaration.
This patch fix thoses style problems.

Signed-off-by: LABBE Corentin <clabbe.montjoie@gmail.com>
---
 drivers/char/hw_random/amd-rng.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c
index 48f6a83..45b7965 100644
--- a/drivers/char/hw_random/amd-rng.c
+++ b/drivers/char/hw_random/amd-rng.c
@@ -31,10 +31,8 @@
 #include <linux/delay.h>
 #include <asm/io.h>
 
-
 #define PFX	KBUILD_MODNAME ": "
 
-
 /*
  * Data for PCI driver interface
  *
@@ -52,7 +50,6 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
 
 static struct pci_dev *amd_pdev;
 
-
 static int amd_rng_data_present(struct hwrng *rng, int wait)
 {
 	u32 pmbase = (u32)rng->priv;
@@ -100,7 +97,6 @@ static void amd_rng_cleanup(struct hwrng *rng)
 	pci_write_config_byte(amd_pdev, 0x40, rnen);
 }
 
-
 static struct hwrng amd_rng = {
 	.name		= "amd",
 	.init		= amd_rng_init,
@@ -109,7 +105,6 @@ static struct hwrng amd_rng = {
 	.data_read	= amd_rng_data_read,
 };
 
-
 static int __init mod_init(void)
 {
 	int err = -ENODEV;
@@ -157,6 +152,7 @@ out:
 static void __exit mod_exit(void)
 {
 	u32 pmbase = (unsigned long)amd_rng.priv;
+
 	release_region(pmbase + 0xF0, 8);
 	hwrng_unregister(&amd_rng);
 }
-- 
2.7.3

^ permalink raw reply related

* Re: [PATCH] Add Ingenic JZ4780 hardware RNG driver
From: PrasannaKumar Muralidharan @ 2016-08-19 13:09 UTC (permalink / raw)
  To: noloader; +Cc: linux-crypto, devicetree, linux-kernel, linux-mips
In-Reply-To: <CAH8yC8ny62Vf63cjtL8bUgGoRr-0BVGvqazs20S4JreJq+OBcg@mail.gmail.com>

> __ARM_FEATURE_UNALIGNED (cf.,
> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0774f/chr1383660321827.html)
> . MIPSEL does not define such a macro.
>
>     # MIPS ci20 creator with GCC 4.6
>     $ gcc -march=native -dM -E - </dev/null | grep -i align
>     #define __BIGGEST_ALIGNMENT__ 8
>
> If the MIPS CPU does not tolerate unaligned data access, then the
> following could SIGBUS:
>
>> +       u32 *data = buf;
>> +       *data = jz4780_rng_readl(jz4780_rng, REG_RNG_DATA);
>
> If GCC emits code that uses the MIPS unaligned load and store
> instructions, then there's probably going to be a performance penalty.
>
> Regardless of what the CPU tolerates, I believe unaligned data access
> is undefined behavior in C/C++. I believe you should memcpy the value
> into the buffer.

I am not sure whether this is required. 'buf' is part of a structure
so I guess it is properly aligned by padding. Not sure though, will
look about this.

^ permalink raw reply

* Re: [PATCH] Add Ingenic JZ4780 hardware RNG driver
From: PrasannaKumar Muralidharan @ 2016-08-19 12:54 UTC (permalink / raw)
  To: noloader-Re5JQEeQqe8AvxtiuMwx3w
  Cc: linux-crypto-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-mips-6z/3iImG2C8G8FEW9MqTrA
In-Reply-To: <CAH8yC8kt-+6tnzAc2bsu6GX4uX1bqVoE8sZXvCS34DDhGhP2XQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

> Please forgive my ignorance Prasanna...
>
> For the JZ4780 I have, there are two registers in play. The first is
> the control register which enables/disables the RNG. The control
> register is named ERNG. The second register is the data register, and
> it produces the random stream. The data register is named RNG. ERNG is
> located at 0x100000D8 and RNG is located at 0x100000DC. This kind of
> confuses me because I don't see where 0x100000D8 is ever added to
> those values (maybe its in the descriptor?):
>
> +#define REG_RNG_CTRL   0x0
> +#define REG_RNG_DATA   0x4

The base address 0x100000D8 is defined in jz4780.dtsi file.
REG_RNG_CTRL and REG_RNG_DATA are offsets. In jz4780_rng_readl and
jz4780_rng_writel functions the ioremap'd base address is added with
offset.

> Also, testing with a userland PoC for the device, you have to throttle
> reads from RNG register. If reads occur with a 0 delay, then the
> random value appears fixed. If the delay is too small, then you can
> watch random values being shifted-in in a barrel like fashion.
> Unfortunately, the manual did not discuss how long to wait for a value
> to be ready. I found spinning in a loop for 5000 was too small and
> witnessed the shifting; while spinning in a loop for 10000 avoided the
> shift observation. I don't what number of JIFFIES that translates to.

I can calculate the speed and make sure the delay is met in the
driver. Thanks a lot for providing this info.

> Finally, from looking at the native Ingenic driver (which was not very
> impressive), they enabled/disabled the RNG register on demand. There
> was also a [possible related] note in the manual about not applying
> VCC for over a second. I can only say "possibly related" because I was
> not sure if the register was part of the controller they were
> discussing. The userland PoC worked fine when enabling/disabling the
> RNG register. So I'm not sure about this (from jz4780_rng_probe):
>
> +       platform_set_drvdata(pdev, jz4780_rng);
> +       jz4780_rng_writel(jz4780_rng, 1, REG_RNG_CTRL);
> +       ret = hwrng_register(&jz4780_rng->rng);
>
> And this (from jz4780_rng_remove):
>
> +       jz4780_rng_writel(jz4780_rng, 0, REG_RNG_CTRL);
> +       hwrng_unregister(&jz4780_rng->rng);
>
> Anyway, I hope that helps you avoid some land mines (if they are present).

Looking at JZ4780 Programmers manual I could not find any info about
VCC. Can you point me to it?
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH] crypto/xor: skip speed test if the xor function is selected automatically
From: Martin Schwidefsky @ 2016-08-19 12:19 UTC (permalink / raw)
  To: Herbert Xu, David S. Miller, linux-crypto; +Cc: Martin Schwidefsky

If the architecture selected the xor function with XOR_SELECT_TEMPLATE
the speed result of the do_xor_speed benchmark is of limited value.
The speed measurement increases the bootup time a little, which can
makes a difference for kernels used in container like virtual machines.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
---
 crypto/xor.c | 40 +++++++++++++++++++---------------------
 1 file changed, 19 insertions(+), 21 deletions(-)

diff --git a/crypto/xor.c b/crypto/xor.c
index 35d6b3a..b8975d9 100644
--- a/crypto/xor.c
+++ b/crypto/xor.c
@@ -109,6 +109,18 @@ calibrate_xor_blocks(void)
 	void *b1, *b2;
 	struct xor_block_template *f, *fastest;
 
+	fastest = NULL;
+
+#ifdef XOR_SELECT_TEMPLATE
+	fastest = XOR_SELECT_TEMPLATE(fastest);
+	if (fastest) {
+		printk(KERN_INFO "xor: automatically using best "
+				 "checksumming function   %-10s\n",
+		       fastest->name);
+		goto out;
+	}
+#endif
+
 	/*
 	 * Note: Since the memory is not actually used for _anything_ but to
 	 * test the XOR speed, we don't really want kmemcheck to warn about
@@ -126,36 +138,22 @@ calibrate_xor_blocks(void)
 	 * all the possible functions, just test the best one
 	 */
 
-	fastest = NULL;
-
-#ifdef XOR_SELECT_TEMPLATE
-		fastest = XOR_SELECT_TEMPLATE(fastest);
-#endif
-
 #define xor_speed(templ)	do_xor_speed((templ), b1, b2)
 
-	if (fastest) {
-		printk(KERN_INFO "xor: automatically using best "
-				 "checksumming function:\n");
-		xor_speed(fastest);
-		goto out;
-	} else {
-		printk(KERN_INFO "xor: measuring software checksum speed\n");
-		XOR_TRY_TEMPLATES;
-		fastest = template_list;
-		for (f = fastest; f; f = f->next)
-			if (f->speed > fastest->speed)
-				fastest = f;
-	}
+	printk(KERN_INFO "xor: measuring software checksum speed\n");
+	XOR_TRY_TEMPLATES;
+	fastest = template_list;
+	for (f = fastest; f; f = f->next)
+		if (f->speed > fastest->speed)
+			fastest = f;
 
 	printk(KERN_INFO "xor: using function: %s (%d.%03d MB/sec)\n",
 	       fastest->name, fastest->speed / 1000, fastest->speed % 1000);
 
 #undef xor_speed
 
- out:
 	free_pages((unsigned long)b1, 2);
-
+out:
 	active_template = fastest;
 	return 0;
 }
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH] Add Ingenic JZ4780 hardware RNG driver
From: Jeffrey Walton @ 2016-08-19 10:55 UTC (permalink / raw)
  To: PrasannaKumar Muralidharan
  Cc: linux-crypto, devicetree, linux-kernel, linux-mips
In-Reply-To: <1471448151-20850-1-git-send-email-prasannatsmkumar@gmail.com>

On Wed, Aug 17, 2016 at 11:35 AM, PrasannaKumar Muralidharan
<prasannatsmkumar@gmail.com> wrote:
> This patch adds support for hardware random number generator present in
> JZ4780 SoC.
>
> Signed-off-by: PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>
> ---
>  ...
> +static int jz4780_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
> +{
> +       struct jz4780_rng *jz4780_rng = container_of(rng, struct jz4780_rng,
> +                                                       rng);
> +       u32 *data = buf;
> +       *data = jz4780_rng_readl(jz4780_rng, REG_RNG_DATA);
> +       return 4;
> +}

My bad, I should have spotted this earlier....

i686, x86_64 and some ARM will sometimes define a macro indicating
unaligned data access is allowed. For example, see
__ARM_FEATURE_UNALIGNED (cf.,
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0774f/chr1383660321827.html)
. MIPSEL does not define such a macro.

    # MIPS ci20 creator with GCC 4.6
    $ gcc -march=native -dM -E - </dev/null | grep -i align
    #define __BIGGEST_ALIGNMENT__ 8

If the MIPS CPU does not tolerate unaligned data access, then the
following could SIGBUS:

> +       u32 *data = buf;
> +       *data = jz4780_rng_readl(jz4780_rng, REG_RNG_DATA);

If GCC emits code that uses the MIPS unaligned load and store
instructions, then there's probably going to be a performance penalty.

Regardless of what the CPU tolerates, I believe unaligned data access
is undefined behavior in C/C++. I believe you should memcpy the value
into the buffer.

Jeff

^ permalink raw reply

* Re: [PATCH] Add Ingenic JZ4780 hardware RNG driver
From: Jeffrey Walton @ 2016-08-19  9:47 UTC (permalink / raw)
  To: PrasannaKumar Muralidharan
  Cc: linux-crypto, devicetree, linux-kernel, linux-mips
In-Reply-To: <1471448151-20850-1-git-send-email-prasannatsmkumar@gmail.com>

On Wed, Aug 17, 2016 at 11:35 AM, PrasannaKumar Muralidharan
<prasannatsmkumar@gmail.com> wrote:
> This patch adds support for hardware random number generator present in
> JZ4780 SoC.
>
> Signed-off-by: PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>
> ---
>  .../devicetree/bindings/rng/ingenic,jz4780-rng.txt |  12 +++
>  MAINTAINERS                                        |   5 +
>  arch/mips/boot/dts/ingenic/jz4780.dtsi             |   7 +-
>  drivers/char/hw_random/Kconfig                     |  14 +++
>  drivers/char/hw_random/Makefile                    |   1 +
>  drivers/char/hw_random/jz4780-rng.c                | 105 +++++++++++++++++++++
>  6 files changed, 143 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/rng/ingenic,jz4780-rng.txt
>  create mode 100644 drivers/char/hw_random/jz4780-rng.c
>
> diff --git a/Documentation/devicetree/bindings/rng/ingenic,jz4780-rng.txt b/Documentation/devicetree/bindings/rng/ingenic,jz4780-rng.txt
> new file mode 100644
> index 0000000..03abf56
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/rng/ingenic,jz4780-rng.txt
> @@ -0,0 +1,12 @@
> +Ingenic jz4780 RNG driver
> +
> +Required properties:
> +- compatible : Should be "ingenic,jz4780-rng"
> +- reg : Specifies base physical address and size of the registers.
> +
> +Example:
> +
> +rng: rng@100000D8 {
> +       compatible = "ingenic,jz4780-rng";
> +       reg = <0x100000D8 0x8>;
> +};
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 08e9efe..c0c66eb 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6002,6 +6002,11 @@ M:       Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
>  S:     Maintained
>  F:     drivers/dma/dma-jz4780.c
>
> +INGENIC JZ4780 HW RNG Driver
> +M:     PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>
> +S:     Maintained
> +F:     drivers/char/hw_random/jz4780-rng.c
> +
>  INTEGRITY MEASUREMENT ARCHITECTURE (IMA)
>  M:     Mimi Zohar <zohar@linux.vnet.ibm.com>
>  M:     Dmitry Kasatkin <dmitry.kasatkin@gmail.com>
> diff --git a/arch/mips/boot/dts/ingenic/jz4780.dtsi b/arch/mips/boot/dts/ingenic/jz4780.dtsi
> index b868b42..f11d139 100644
> --- a/arch/mips/boot/dts/ingenic/jz4780.dtsi
> +++ b/arch/mips/boot/dts/ingenic/jz4780.dtsi
> @@ -36,7 +36,7 @@
>
>         cgu: jz4780-cgu@10000000 {
>                 compatible = "ingenic,jz4780-cgu";
> -               reg = <0x10000000 0x100>;
> +               reg = <0x10000000 0xD8>;
>
>                 clocks = <&ext>, <&rtc>;
>                 clock-names = "ext", "rtc";
> @@ -44,6 +44,11 @@
>                 #clock-cells = <1>;
>         };
>
> +       rng: jz4780-rng@100000D8 {
> +               compatible = "ingenic,jz4780-rng";
> +               reg = <0x100000D8 0x8>;
> +       };
> +
>         uart0: serial@10030000 {
>                 compatible = "ingenic,jz4780-uart";
>                 reg = <0x10030000 0x100>;
> diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
> index 56ad5a59..c336fe8 100644
> --- a/drivers/char/hw_random/Kconfig
> +++ b/drivers/char/hw_random/Kconfig
> @@ -294,6 +294,20 @@ config HW_RANDOM_POWERNV
>
>           If unsure, say Y.
>
> +config HW_RANDOM_JZ4780
> +       tristate "JZ4780 HW random number generator support"
> +       depends on MACH_INGENIC
> +       depends on HAS_IOMEM
> +       default HW_RANDOM
> +       ---help---
> +         This driver provides kernel-side support for the Random Number
> +         Generator hardware found on JZ4780 SOCs.
> +
> +         To compile this driver as a module, choose M here: the
> +         module will be called jz4780-rng.
> +
> +         If unsure, say Y.
> +
>  config HW_RANDOM_EXYNOS
>         tristate "EXYNOS HW random number generator support"
>         depends on ARCH_EXYNOS || COMPILE_TEST
> diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
> index 04bb0b0..a155066 100644
> --- a/drivers/char/hw_random/Makefile
> +++ b/drivers/char/hw_random/Makefile
> @@ -26,6 +26,7 @@ obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o
>  obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o
>  obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o
>  obj-$(CONFIG_HW_RANDOM_HISI)   += hisi-rng.o
> +obj-$(CONFIG_HW_RANDOM_JZ4780) += jz4780-rng.o
>  obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o
>  obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o
>  obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o
> diff --git a/drivers/char/hw_random/jz4780-rng.c b/drivers/char/hw_random/jz4780-rng.c
> new file mode 100644
> index 0000000..c9d2cde
> --- /dev/null
> +++ b/drivers/char/hw_random/jz4780-rng.c
> @@ -0,0 +1,105 @@
> +/*
> + * jz4780-rng.c - Random Number Generator driver for J4780
> + *
> + * Copyright 2016 (C) PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>
> + *
> + * This file is licensed under  the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/hw_random.h>
> +#include <linux/device.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include <linux/err.h>
> +
> +#define REG_RNG_CTRL   0x0
> +#define REG_RNG_DATA   0x4
> +
> +struct jz4780_rng {
> +       struct device *dev;
> +       struct hwrng rng;
> +       void __iomem *mem;
> +};
> +
> +static u32 jz4780_rng_readl(struct jz4780_rng *rng, u32 offset)
> +{
> +       return readl(rng->mem + offset);
> +}
> +
> +static void jz4780_rng_writel(struct jz4780_rng *rng, u32 val, u32 offset)
> +{
> +       writel(val, rng->mem + offset);
> +}
> +
> +static int jz4780_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
> +{
> +       struct jz4780_rng *jz4780_rng = container_of(rng, struct jz4780_rng,
> +                                                       rng);
> +       u32 *data = buf;
> +       *data = jz4780_rng_readl(jz4780_rng, REG_RNG_DATA);
> +       return 4;
> +}
> +
> +static int jz4780_rng_probe(struct platform_device *pdev)
> +{
> +       struct jz4780_rng *jz4780_rng;
> +       struct resource *res;
> +       resource_size_t size;
> +       int ret;
> +
> +       jz4780_rng = devm_kzalloc(&pdev->dev, sizeof(struct jz4780_rng),
> +                                       GFP_KERNEL);
> +       if (!jz4780_rng)
> +               return -ENOMEM;
> +
> +       jz4780_rng->dev = &pdev->dev;
> +       jz4780_rng->rng.name = "jz4780";
> +       jz4780_rng->rng.read = jz4780_rng_read;
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       size = resource_size(res);
> +
> +       jz4780_rng->mem = devm_ioremap(&pdev->dev, res->start, size);
> +       if (IS_ERR(jz4780_rng->mem))
> +               return PTR_ERR(jz4780_rng->mem);
> +
> +       platform_set_drvdata(pdev, jz4780_rng);
> +       jz4780_rng_writel(jz4780_rng, 1, REG_RNG_CTRL);
> +       ret = hwrng_register(&jz4780_rng->rng);
> +
> +       return ret;
> +}
> +
> +static int jz4780_rng_remove(struct platform_device *pdev)
> +{
> +       struct jz4780_rng *jz4780_rng = platform_get_drvdata(pdev);
> +
> +       jz4780_rng_writel(jz4780_rng, 0, REG_RNG_CTRL);
> +       hwrng_unregister(&jz4780_rng->rng);
> +
> +       return 0;
> +}
> +
> +static const struct of_device_id jz4780_rng_dt_match[] = {
> +       { .compatible = "ingenic,jz4780-rng", },
> +       { },
> +};
> +MODULE_DEVICE_TABLE(of, jz4780_rng_dt_match);
> +
> +static struct platform_driver jz4780_rng_driver = {
> +       .driver         = {
> +               .name   = "jz4780-rng",
> +               .of_match_table = jz4780_rng_dt_match,
> +       },
> +       .probe          = jz4780_rng_probe,
> +       .remove         = jz4780_rng_remove,
> +};
> +module_platform_driver(jz4780_rng_driver);
> +
> +MODULE_DESCRIPTION("Ingenic JZ4780 H/W Random Number Generator driver");
> +MODULE_AUTHOR("PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>");
> +MODULE_LICENSE("GPL");
> --

Please forgive my ignorance Prasanna...

For the JZ4780 I have, there are two registers in play. The first is
the control register which enables/disables the RNG. The control
register is named ERNG. The second register is the data register, and
it produces the random stream. The data register is named RNG. ERNG is
located at 0x100000D8 and RNG is located at 0x100000DC. This kind of
confuses me because I don't see where 0x100000D8 is ever added to
those values (maybe its in the descriptor?):

+#define REG_RNG_CTRL   0x0
+#define REG_RNG_DATA   0x4


Also, testing with a userland PoC for the device, you have to throttle
reads from RNG register. If reads occur with a 0 delay, then the
random value appears fixed. If the delay is too small, then you can
watch random values being shifted-in in a barrel like fashion.
Unfortunately, the manual did not discuss how long to wait for a value
to be ready. I found spinning in a loop for 5000 was too small and
witnessed the shifting; while spinning in a loop for 10000 avoided the
shift observation. I don't what number of JIFFIES that translates to.


Finally, from looking at the native Ingenic driver (which was not very
impressive), they enabled/disabled the RNG register on demand. There
was also a [possible related] note in the manual about not applying
VCC for over a second. I can only say "possibly related" because I was
not sure if the register was part of the controller they were
discussing. The userland PoC worked fine when enabling/disabling the
RNG register. So I'm not sure about this (from jz4780_rng_probe):

+       platform_set_drvdata(pdev, jz4780_rng);
+       jz4780_rng_writel(jz4780_rng, 1, REG_RNG_CTRL);
+       ret = hwrng_register(&jz4780_rng->rng);

And this (from jz4780_rng_remove):

+       jz4780_rng_writel(jz4780_rng, 0, REG_RNG_CTRL);
+       hwrng_unregister(&jz4780_rng->rng);

Anyway, I hope that helps you avoid some land mines (if they are present).

Jeff

^ permalink raw reply

* Re: [PATCH v6 0/5] /dev/random - a new approach
From: Pavel Machek @ 2016-08-19  7:48 UTC (permalink / raw)
  To: Theodore Ts'o, Stephan Mueller, herbert, sandyinchina,
	Jason Cooper, John Denker, H. Peter Anvin, Joe Perches,
	George Spelvin, linux-crypto, linux-kernel
In-Reply-To: <20160819024947.GA10888@thunk.org>

Hi!

> > From my point of view, it would make sense to factor time from RTC and
> > mac addresses into the initial hash. Situation in the paper was so bad
> > some devices had _completely identical_ keys. We should be able to do
> > better than that.
> 
> We fixed that **years** ago.  In fact, the authors shared with me an
> early look at that paper and I implemented add_device_entropy() over
> the July 4th weekend back in 2012.  So we are indeed mixing in MAC
> addresses and the hardware clock (if it is initialized that early).
> In fact that was one of the first things that I did.  Note that this

Ok, thanks.

> > BTW... 128 interrupts... that's 1.3 seconds, right? Would it make
> > sense to wait two seconds if urandom use is attempted before it is
> > ready?
> 
> That really depends on the system.  We can't assume that people are
> using systems with a 100Hz clock interrupt.  More often than not
> people are using tickless kernels these days.  That's actually the
> problem with changing /dev/urandom to block until things are
> initialized.

Ok, let me check:

config HZ_PERIODIC
config NO_HZ_IDLE
config NO_HZ_FULL

in HZ_PERIODIC, there should be no problem.

NO_HZ_IDLE... should not be a problem either. We can easily make sure
that cpu's are not idle, something like 

     while (not_enough_entropy())
     	   schedule()

NO_HZ_FULL.... first, help text seems to imply that timer ticks still
happen when cpu is in kernel, and second, there is always one CPU that
handles timer ticks. So we are still ok.

So I believe we should add the wait to urandom. One second delay in
rare cases sounds better than alternatives.

Best regards,
									Pavel
PS: Are there systems where the timer interrupt is the only source of time?
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

^ permalink raw reply

* Re: [PATCHv3 net-next 0/4] crypto/chcr: Add support for Chelsio Crypto Driver
From: David Miller @ 2016-08-19  7:01 UTC (permalink / raw)
  To: herbert
  Cc: hariprasad, netdev, linux-crypto, atul.gupta, yeshaswi, jlulla,
	harsh
In-Reply-To: <20160819061543.GA20764@gondor.apana.org.au>

From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Fri, 19 Aug 2016 14:15:43 +0800

> On Thu, Aug 18, 2016 at 11:11:01PM -0700, David Miller wrote:
>> From: Hariprasad Shenai <hariprasad@chelsio.com>
>> Date: Wed, 17 Aug 2016 12:33:02 +0530
>> 
>> > This patch series adds support for Chelsio Crypto driver. 
>> 
>> Herbert, what do you want to do with this?  I can push it via
>> net-next if you like.
> 
> Sure thing, the crypto part looks good to me.  Thanks Dave!

Great, done.

^ permalink raw reply

* Re: [PATCHv3 net-next 0/4] crypto/chcr: Add support for Chelsio Crypto Driver
From: Herbert Xu @ 2016-08-19  6:15 UTC (permalink / raw)
  To: David Miller
  Cc: hariprasad, netdev, linux-crypto, atul.gupta, yeshaswi, jlulla,
	harsh
In-Reply-To: <20160818.231101.728993368913367217.davem@davemloft.net>

On Thu, Aug 18, 2016 at 11:11:01PM -0700, David Miller wrote:
> From: Hariprasad Shenai <hariprasad@chelsio.com>
> Date: Wed, 17 Aug 2016 12:33:02 +0530
> 
> > This patch series adds support for Chelsio Crypto driver. 
> 
> Herbert, what do you want to do with this?  I can push it via
> net-next if you like.

Sure thing, the crypto part looks good to me.  Thanks Dave!
-- 
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

* Re: [PATCHv3 net-next 3/4] chcr: Support for Chelsio's Crypto Hardware
From: Herbert Xu @ 2016-08-19  6:15 UTC (permalink / raw)
  To: Hariprasad Shenai
  Cc: netdev, linux-crypto, davem, atul.gupta, yeshaswi, jlulla, harsh
In-Reply-To: <1471417386-14026-4-git-send-email-hariprasad@chelsio.com>

On Wed, Aug 17, 2016 at 12:33:05PM +0530, Hariprasad Shenai wrote:
> The Chelsio's Crypto Hardware can perform the following operations:
> SHA1, SHA224, SHA256, SHA384 and SHA512, HMAC(SHA1), HMAC(SHA224),
> HMAC(SHA256), HMAC(SHA384), HAMC(SHA512), AES-128-CBC, AES-192-CBC,
> AES-256-CBC, AES-128-XTS, AES-256-XTS
> 
> This patch implements the driver for above mentioned features. This
> driver is an Upper Layer Driver which is attached to Chelsio's LLD
> (cxgb4) and uses the queue allocated by the LLD for sending the crypto
> requests to the Hardware and receiving the responses from it.
> 
> The crypto operations can be performed by Chelsio's hardware from the
> userspace applications and/or from within the kernel space using the
> kernel's crypto API.
> 
> The above mentioned crypto features have been tested using kernel's
> tests mentioned in testmgr.h. They also have been tested from user
> space using libkcapi and Openssl.
> 
> Signed-off-by: Atul Gupta <atul.gupta@chelsio.com>
> Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>

Acked-by: Herbert Xu <herbert@gondor.apana.org.au>
-- 
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

* Re: [PATCHv3 net-next 0/4] crypto/chcr: Add support for Chelsio Crypto Driver
From: David Miller @ 2016-08-19  6:11 UTC (permalink / raw)
  To: hariprasad
  Cc: netdev, linux-crypto, herbert, atul.gupta, yeshaswi, jlulla,
	harsh
In-Reply-To: <1471417386-14026-1-git-send-email-hariprasad@chelsio.com>

From: Hariprasad Shenai <hariprasad@chelsio.com>
Date: Wed, 17 Aug 2016 12:33:02 +0530

> This patch series adds support for Chelsio Crypto driver. 

Herbert, what do you want to do with this?  I can push it via
net-next if you like.

^ permalink raw reply

* Re: [PATCH v6 0/5] /dev/random - a new approach
From: Herbert Xu @ 2016-08-19  5:56 UTC (permalink / raw)
  To: Theodore Ts'o, Pavel Machek, Stephan Mueller, sandyinchina,
	Jason Cooper, John Denker, H. Peter Anvin, Joe Perches,
	George Spelvin, linux-crypto, linux-kernel
In-Reply-To: <20160819024947.GA10888@thunk.org>

On Thu, Aug 18, 2016 at 10:49:47PM -0400, Theodore Ts'o wrote:
>
> That really depends on the system.  We can't assume that people are
> using systems with a 100Hz clock interrupt.  More often than not
> people are using tickless kernels these days.  That's actually the
> problem with changing /dev/urandom to block until things are
> initialized.

Couldn't we disable tickless until urandom has been seeded? In fact
perhaps we should accelerate the timer interrupt rate until it has
been seeded?

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

* Re: [PATCH -next] crypto: fix missing unlock on error in sun4i_hash()
From: Corentin LABBE @ 2016-08-19  5:40 UTC (permalink / raw)
  To: Wei Yongjun, Herbert Xu, David S. Miller, Maxime Ripard,
	Chen-Yu Tsai
  Cc: linux-crypto, linux-arm-kernel
In-Reply-To: <1471560130-5265-1-git-send-email-weiyj.lk@gmail.com>

On 19/08/2016 00:42, Wei Yongjun wrote:
> Add the missing unlock before return from function sun4i_hash()
> in the error handling case.
> 
> Fixes: 477d9b2e591b ("crypto: sun4i-ss - unify update/final function")
> Signed-off-by: Wei Yongjun <weiyj.lk@gmail.com>
> ---
>  drivers/crypto/sunxi-ss/sun4i-ss-hash.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
> index 2ee3b59..de66f47 100644
> --- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
> +++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
> @@ -245,6 +245,7 @@ int sun4i_hash(struct ahash_request *areq)
>  		if (end > areq->nbytes || areq->nbytes - end > 63) {
>  			dev_err(ss->dev, "ERROR: Bound error %u %u\n",
>  				end, areq->nbytes);
> +			spin_unlock(&ss->slock);
>  			return -EINVAL;
>  		}
>  	} else {
> 

Hello

Thanks for the finding, but it is better in that case to use the goto release_ss since it need also to stop the device.

Regards

LABBE Corentin

^ permalink raw reply

* Re: [PATCH v6 0/5] /dev/random - a new approach
From: Theodore Ts'o @ 2016-08-19  2:49 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Stephan Mueller, herbert, sandyinchina, Jason Cooper, John Denker,
	H. Peter Anvin, Joe Perches, George Spelvin, linux-crypto,
	linux-kernel
In-Reply-To: <20160818183923.GA24817@amd>

On Thu, Aug 18, 2016 at 08:39:23PM +0200, Pavel Machek wrote:
> 
> But this is the scary part. Not limited to ssh. "We perform the
> largest ever network survey of TLS and SSH servers and present
> evidence that vulnerable keys are surprisingly widespread. We find
> that 0.75% of TLS certificates share keys due to insufficient entropy
> during key generation, and we suspect that another 1.70% come from the
> same faulty implementations and may be susceptible to compromise.
> Even more alarmingly, we are able to obtain RSA private keys for 0.50%
> of TLS hosts and 0.03% of SSH hosts, because their public keys shared
> nontrivial common factors due to entropy problems, and DSA private
> keys for 1.03% of SSH hosts, because of insufficient signature
> randomness"
> 
> https://factorable.net/weakkeys12.conference.pdf

That's a very old paper, and we've made a lot of changes since then.
Before that we weren't accumulating entropy from the interrupt
handler, but only from spinning disk drives, some network interrupts
(but not from all NIC's; it was quite arbitrary), and keyboard and
mouse interrupts.  So hours and hours could go by and you still
wouldn't have accumulated much entropy.

> From my point of view, it would make sense to factor time from RTC and
> mac addresses into the initial hash. Situation in the paper was so bad
> some devices had _completely identical_ keys. We should be able to do
> better than that.

We fixed that **years** ago.  In fact, the authors shared with me an
early look at that paper and I implemented add_device_entropy() over
the July 4th weekend back in 2012.  So we are indeed mixing in MAC
addresses and the hardware clock (if it is initialized that early).
In fact that was one of the first things that I did.  Note that this
doesn't really add much entropy, but it does prevent the GCD attack
from demonstrating completely identical keys.  Hence, we had
remediations in the mainline kernel before the factorable.net paper
was published (not that really helped with devices with embedded
Linux, especially since device manufactures don't see anything wrong
with shipping machines with kernels that are years and years out of
date --- OTOH, these systems were probably also shipping with dozens
of known exploitable holes in userspace, if that's any comfort.
Probably not much if you were planning on deploying lots of IOT
devices in your home network.  :-)

> BTW... 128 interrupts... that's 1.3 seconds, right? Would it make
> sense to wait two seconds if urandom use is attempted before it is
> ready?

That really depends on the system.  We can't assume that people are
using systems with a 100Hz clock interrupt.  More often than not
people are using tickless kernels these days.  That's actually the
problem with changing /dev/urandom to block until things are
initialized.

If you do that, then on some system Python will use /dev/urandom to
initialize a salt used by the Python dictionaries, to protect against
DOS attacks when Python is used to run web scripts.  This is a
completely irrelevant reason when Python is being used for systemd
generator scripts in early boot, and if /dev/urandom were to block,
then the system ends up doing nothing, and on a tickless kernels hours
and hours can go by on a VM and Python would still be blocked on
/dev/urandom.  And since none of the system scripts are running, there
are no interrupts, and so Python ends up blocking on /dev/urandom for
a very long time.  (Eventually someone will start trying to brute
force passwords on the VM's ssh port, assuming that the VM's firewall
rules allow this, and that will cause interrupts that will eventually
initialize /dev/urandom.  But that could take hours.)

And this, boys and girls, is why we can't make /dev/urandom block
until its pool is initialized.  There's too great of a chance that we
will break userspace, and then Linus will yell at us and revert the
commit.

						- Ted

^ permalink raw reply

* [PATCH] crypto: qat - fix aes-xts key sizes
From: Giovanni Cabiddu @ 2016-08-18 18:53 UTC (permalink / raw)
  To: herbert; +Cc: linux-crypto, Giovanni Cabiddu

Increase value of supported key sizes for qat_aes_xts.
aes-xts keys consists of keys of equal size concatenated.

Reported-by: Wenqian Yu <wenqian.yu@intel.com>
Signed-off-by: Giovanni Cabiddu <giovanni.cabiddu@intel.com>
---
 drivers/crypto/qat/qat_common/qat_algs.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
index 769148d..20f35df 100644
--- a/drivers/crypto/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_algs.c
@@ -1260,8 +1260,8 @@ static struct crypto_alg qat_algs[] = { {
 			.setkey = qat_alg_ablkcipher_xts_setkey,
 			.decrypt = qat_alg_ablkcipher_decrypt,
 			.encrypt = qat_alg_ablkcipher_encrypt,
-			.min_keysize = AES_MIN_KEY_SIZE,
-			.max_keysize = AES_MAX_KEY_SIZE,
+			.min_keysize = 2 * AES_MIN_KEY_SIZE,
+			.max_keysize = 2 * AES_MAX_KEY_SIZE,
 			.ivsize = AES_BLOCK_SIZE,
 		},
 	},
-- 
1.7.4.1

^ permalink raw reply related

* Re: [PATCH v6 0/5] /dev/random - a new approach
From: Theodore Ts'o @ 2016-08-18 17:27 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Stephan Mueller, herbert, sandyinchina, Jason Cooper, John Denker,
	H. Peter Anvin, Joe Perches, George Spelvin, linux-crypto,
	linux-kernel
In-Reply-To: <20160817214254.GA22438@amd>

On Wed, Aug 17, 2016 at 11:42:55PM +0200, Pavel Machek wrote:
> 
> Actually.. I'm starting to believe that getting enough entropy before
> userspace starts is more important than pretty much anything else.
> 
> We only "need" 64-bits of entropy, AFAICT. If it passes statistical
> tests, I'd use it... for initial bringup.

Definitely not 64 bits.  Back in *1996* the estimate was that we
needed at least 75-bits in order to be protected against brute force
attacks.  It's been two *deacdes* years later, and granted Moore's law
has ceased to apply in the last couple of years, but I'm sure 64 bits
is not enough.

What is your specific concern vis-a-vis when userspace starts?  We now
print a warning if someone tries to draw from /dev/urandom, and so it
should be easy to see if someone is doing something dangerous.  The
have only been known cases (at last as far asI know where) where some
software was doing something as *insane* as to create keys right out
of the box was.  One was ssh, and at least on a modern Debian system,
that doesn't happen until fairly late in the process:

% systemd-analyze critical-chain ssh.service
The time after the unit is active or started is printed after the "@" character.
The time the unit takes to start is printed after the "+" character.

ssh.service +888ms
└─network.target @31.473s
  └─wpa_supplicant.service @32.958s +770ms
    └─basic.target @19.479s
      └─sockets.target @19.479s
        └─acpid.socket @19.479s
          └─sysinit.target @19.414s
            └─systemd-timesyncd.service @18.079s +1.330s
              └─systemd-tmpfiles-setup.service @17.512s +78ms
                └─local-fs.target @17.501s
                  └─run-user-15806.mount @43.047s
                    └─local-fs-pre.target @16.616s
                      └─systemd-tmpfiles-setup-dev.service @755ms +930ms
                        └─kmod-static-nodes.service @729ms +17ms
                          └─system.slice @653ms
                            └─-.slice @608ms

The other was HP, which was generating an RSA key very shortly after
the first time the printer was powered on.

> We can switch to more conservative estimates when system is fully
> running. But IMO it is very important to get _some_ randomness at the
> begining...

We're doing this already in the latest getrandom(2) implementation.
For the purposes of initializing the crng, we assume that each
interrupt has a single bit of entropy.  So it requires 128 initerrupts
for getrandom(2) to be fully initialized.  I'm actually worried that
this is too high as it is for architectures that don't have a
fine-grained clock.  Given that on many of these embedded platforms
there is a oscillator which drives all of the clocks and subsystems,
it just doesn't make *sense* that than each interrupt could result in
5-6 bits of entropy, no matter what a magical statistical formula
might say.

(Creation of some completely determinsitic sequences that cause the
magical statistcal formulas to claim a vast number of entropy bits is
left as an exercise to the reader.)

Cheers, 

							- Ted

^ permalink raw reply

* Re: [PATCH] Add Ingenic JZ4780 hardware RNG driver
From: Rob Herring @ 2016-08-19  0:59 UTC (permalink / raw)
  To: PrasannaKumar Muralidharan
  Cc: mpm, herbert, mark.rutland, ralf, davem, geert, akpm, gregkh,
	mchehab, linux, boris.brezillon, harvey.hunt, alex.smith,
	daniel.thompson, lee.jones, f.fainelli, kieran, krzk,
	joshua.henderson, yendapally.reddy, narmstrong, wangkefeng.wang,
	chunkeey, noltari, linus.walleij, pankaj.dev, mathieu.poirier,
	linux-crypto, devicetree, linux-kernel, linux-mips
In-Reply-To: <1471448151-20850-1-git-send-email-prasannatsmkumar@gmail.com>

On Wed, Aug 17, 2016 at 09:05:51PM +0530, PrasannaKumar Muralidharan wrote:
> This patch adds support for hardware random number generator present in
> JZ4780 SoC.
> 
> Signed-off-by: PrasannaKumar Muralidharan <prasannatsmkumar@gmail.com>
> ---
>  .../devicetree/bindings/rng/ingenic,jz4780-rng.txt |  12 +++

Acked-by: Rob Herring <robh@kernel.org>

>  MAINTAINERS                                        |   5 +
>  arch/mips/boot/dts/ingenic/jz4780.dtsi             |   7 +-
>  drivers/char/hw_random/Kconfig                     |  14 +++
>  drivers/char/hw_random/Makefile                    |   1 +
>  drivers/char/hw_random/jz4780-rng.c                | 105 +++++++++++++++++++++
>  6 files changed, 143 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/rng/ingenic,jz4780-rng.txt
>  create mode 100644 drivers/char/hw_random/jz4780-rng.c

^ permalink raw reply

* [PATCH -next] crypto: fix missing unlock on error in sun4i_hash()
From: Wei Yongjun @ 2016-08-18 22:42 UTC (permalink / raw)
  To: Corentin Labbe, Herbert Xu, David S. Miller, Maxime Ripard,
	Chen-Yu Tsai
  Cc: Wei Yongjun, linux-crypto, linux-arm-kernel

Add the missing unlock before return from function sun4i_hash()
in the error handling case.

Fixes: 477d9b2e591b ("crypto: sun4i-ss - unify update/final function")
Signed-off-by: Wei Yongjun <weiyj.lk@gmail.com>
---
 drivers/crypto/sunxi-ss/sun4i-ss-hash.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
index 2ee3b59..de66f47 100644
--- a/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
+++ b/drivers/crypto/sunxi-ss/sun4i-ss-hash.c
@@ -245,6 +245,7 @@ int sun4i_hash(struct ahash_request *areq)
 		if (end > areq->nbytes || areq->nbytes - end > 63) {
 			dev_err(ss->dev, "ERROR: Bound error %u %u\n",
 				end, areq->nbytes);
+			spin_unlock(&ss->slock);
 			return -EINVAL;
 		}
 	} else {

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox