Merge branch 'kerrisk/remove_migrated_man7' of git://git.kernel.org/pub/scm/linux/kernel/git/mtk/keyutils.git

"As discussed face-to-face and by email, there are a number of
 man pages in keyutils that document kernel APIs. The more natural
 home for these pages is Linux man-pages. I've already migrated
 the pages listed below into Linux man-pages, and subsequently
 enhanced various pages. They'll be released with the next release of
 man-pages (around the end of Feb 2017)."

Signed-off-by: David Howells <dhowells@redhat.com>
diff --git a/.gitignore b/.gitignore
index 1caa791..0ac39ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,8 @@
 *.so
 *.a
 *.so.*
-keyctl
-request-key
-key.dns_resolver
-rpmbuild
+/keyctl
+/request-key
+/key.dns_resolver
+/rpmbuild
+test.out
diff --git a/Makefile b/Makefile
index 5395c0b..824bbbf 100644
--- a/Makefile
+++ b/Makefile
@@ -194,6 +194,7 @@
 	$(LNS) keyctl_link.3 $(DESTDIR)$(MAN3)/keyctl_unlink.3
 	$(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
 	$(INSTALL) -D -m 0644 keyutils.h $(DESTDIR)$(INCLUDEDIR)/keyutils.h
 
 ###############################################################################
@@ -217,7 +218,7 @@
 	$(RM) debugfiles.list debugsources.list
 
 distclean: clean
-	$(RM) -r rpmbuild
+	$(RM) -r rpmbuild $(TARBALL)
 
 ###############################################################################
 #
@@ -226,7 +227,7 @@
 ###############################################################################
 $(ZTARBALL):
 	git archive --prefix=keyutils-$(VERSION)/ --format tar -o $(TARBALL) HEAD
-	bzip2 -9 $(TARBALL)
+	bzip2 -9 <$(TARBALL) >$(ZTARBALL)
 
 tarball: $(ZTARBALL)
 
@@ -236,9 +237,10 @@
 #
 ###############################################################################
 SRCBALL	:= rpmbuild/SOURCES/$(TARBALL)
+ZSRCBALL := rpmbuild/SOURCES/$(ZTARBALL)
 
 BUILDID	:= .local
-dist	:= $(word 2,$(shell grep "%dist" /etc/rpm/macros.dist))
+dist	:= $(word 2,$(shell grep -r "^%dist" /etc/rpm /usr/lib/rpm))
 release	:= $(word 2,$(shell grep ^Release: $(SPECFILE)))
 release	:= $(subst %{?dist},$(dist),$(release))
 release	:= $(subst %{?buildid},$(BUILDID),$(release))
@@ -246,12 +248,12 @@
 SRPM	:= rpmbuild/SRPMS/keyutils-$(rpmver).src.rpm
 
 RPMBUILDDIRS := \
-		--define "_srcrpmdir $(CURDIR)/rpmbuild/SRPMS" \
-		--define "_rpmdir $(CURDIR)/rpmbuild/RPMS" \
-		--define "_sourcedir $(CURDIR)/rpmbuild/SOURCES" \
-		--define "_specdir $(CURDIR)/rpmbuild/SPECS" \
-		--define "_builddir $(CURDIR)/rpmbuild/BUILD" \
-		--define "_buildrootdir $(CURDIR)/rpmbuild/BUILDROOT"
+	--define "_srcrpmdir $(CURDIR)/rpmbuild/SRPMS" \
+	--define "_rpmdir $(CURDIR)/rpmbuild/RPMS" \
+	--define "_sourcedir $(CURDIR)/rpmbuild/SOURCES" \
+	--define "_specdir $(CURDIR)/rpmbuild/SPECS" \
+	--define "_builddir $(CURDIR)/rpmbuild/BUILD" \
+	--define "_buildrootdir $(CURDIR)/rpmbuild/BUILDROOT"
 
 RPMFLAGS := \
 	--define "buildid $(BUILDID)"
@@ -261,8 +263,8 @@
 	chmod ug-s rpmbuild
 	mkdir -p rpmbuild/{SPECS,SOURCES,BUILD,BUILDROOT,RPMS,SRPMS}
 	git archive --prefix=keyutils-$(VERSION)/ --format tar -o $(SRCBALL) HEAD
-	bzip2 -9f $(SRCBALL)
-	rpmbuild -ts $(SRCBALL).bz2 --define "_srcrpmdir rpmbuild/SRPMS" $(RPMFLAGS)
+	bzip2 -9 <$(SRCBALL) >$(ZSRCBALL)
+	rpmbuild -ts $(ZSRCBALL) --define "_srcrpmdir rpmbuild/SRPMS" $(RPMFLAGS)
 	rpmbuild --rebuild $(SRPM) $(RPMBUILDDIRS) $(RPMFLAGS)
 
 rpmlint: rpm
diff --git a/keyctl.c b/keyctl.c
index 7e5ce6f..801a864 100644
--- a/keyctl.c
+++ b/keyctl.c
@@ -66,6 +66,7 @@
 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[]);
 
 const struct command commands[] = {
 	{ act_keyctl___version,	"--version",	"" },
@@ -74,6 +75,7 @@
 	{ act_keyctl_chown,	"chown",	"<key> <uid>" },
 	{ act_keyctl_clear,	"clear",	"<keyring>" },
 	{ act_keyctl_describe,	"describe",	"<keyring>" },
+	{ act_keyctl_dh_compute, "dh_compute",	"<private> <prime> <base>" },
 	{ act_keyctl_instantiate, "instantiate","<key> <data> <keyring>" },
 	{ act_keyctl_invalidate,"invalidate",	"<key>" },
 	{ act_keyctl_get_persistent, "get_persistent", "<keyring> [<uid>]" },
@@ -1627,6 +1629,56 @@
 
 /*****************************************************************************/
 /*
+ * Perform Diffie-Hellman computation
+ */
+static void act_keyctl_dh_compute(int argc, char *argv[])
+{
+	key_serial_t priv, prime, base;
+	void *buffer;
+	char *p;
+	int ret, sep, col;
+
+	if (argc != 4)
+		format();
+
+	priv = get_key_id(argv[1]);
+	prime = get_key_id(argv[2]);
+	base = get_key_id(argv[3]);
+
+	ret = keyctl_dh_compute_alloc(priv, prime, base, &buffer);
+	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++;
+
+		col++;
+		if (col % 32 == 0)
+			sep = '\n';
+		else if (col % 4 == 0)
+			sep = ' ';
+
+	} while (--ret > 0);
+
+	printf("\n");
+	exit(0);
+}
+
+/*****************************************************************************/
+/*
  * parse a key identifier
  */
 static key_serial_t get_key_id(char *arg)
diff --git a/keyutils.c b/keyutils.c
index 8856c8a..a6325d0 100644
--- a/keyutils.c
+++ b/keyutils.c
@@ -234,6 +234,16 @@
 	return keyctl(KEYCTL_GET_PERSISTENT, uid, id);
 }
 
+long keyctl_dh_compute(key_serial_t priv, key_serial_t prime,
+		       key_serial_t base, char *buffer, size_t buflen)
+{
+	struct keyctl_dh_params params = { .priv = priv,
+					   .prime = prime,
+					   .base = base };
+
+	return keyctl(KEYCTL_DH_COMPUTE, &params, buffer, buflen, 0);
+}
+
 /*****************************************************************************/
 /*
  * fetch key description into an allocated buffer
@@ -343,6 +353,38 @@
 	return ret - 1;
 }
 
+/*****************************************************************************/
+/*
+ * fetch DH computation results into an allocated buffer
+ * - resulting buffer has an extra NUL added to the end
+ * - returns count (not including extraneous NUL)
+ */
+int keyctl_dh_compute_alloc(key_serial_t priv, key_serial_t prime,
+			    key_serial_t base, void **_buffer)
+{
+	char *buf;
+	long buflen, ret;
+
+	ret = keyctl_dh_compute(priv, prime, base, NULL, 0);
+	if (ret < 0)
+		return -1;
+
+	buflen = ret;
+	buf = malloc(buflen + 1);
+	if (!buf)
+		return -1;
+
+	ret = keyctl_dh_compute(priv, prime, base, buf, buflen);
+	if (ret < 0) {
+		free(buf);
+		return -1;
+	}
+
+	buf[ret] = 0;
+	*_buffer = buf;
+	return ret;
+}
+
 /*
  * Depth-first recursively apply a function over a keyring tree
  */
diff --git a/keyutils.h b/keyutils.h
index fc8495d..a69fa7a 100644
--- a/keyutils.h
+++ b/keyutils.h
@@ -99,6 +99,14 @@
 #define KEYCTL_INSTANTIATE_IOV		20	/* instantiate a partially constructed key */
 #define KEYCTL_INVALIDATE		21	/* invalidate a key */
 #define KEYCTL_GET_PERSISTENT		22	/* get a user's persistent keyring */
+#define KEYCTL_DH_COMPUTE		23	/* Compute Diffie-Hellman values */
+
+/* keyctl structures */
+struct keyctl_dh_params {
+	key_serial_t priv;
+	key_serial_t prime;
+	key_serial_t base;
+};
 
 /*
  * syscall wrappers
@@ -153,6 +161,8 @@
 				   key_serial_t ringid);
 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 priv, key_serial_t prime,
+			      key_serial_t base, char *buffer, size_t buflen);
 
 /*
  * utilities
@@ -160,6 +170,8 @@
 extern int keyctl_describe_alloc(key_serial_t id, char **_buffer);
 extern int keyctl_read_alloc(key_serial_t id, void **_buffer);
 extern int keyctl_get_security_alloc(key_serial_t id, char **_buffer);
+extern int keyctl_dh_compute_alloc(key_serial_t priv, key_serial_t prime,
+				   key_serial_t base, void **_buffer);
 
 typedef int (*recursive_key_scanner_t)(key_serial_t parent, key_serial_t key,
 				       char *desc, int desc_len, void *data);
diff --git a/keyutils.spec b/keyutils.spec
index 3312f84..895e085 100644
--- a/keyutils.spec
+++ b/keyutils.spec
@@ -2,7 +2,7 @@
 %define verminor 5.9
 %define version %{vermajor}.%{verminor}
 %define libapivermajor 1
-%define libapiversion %{libapivermajor}.5
+%define libapiversion %{libapivermajor}.6
 
 # % define buildid .local
 
diff --git a/man/find_key_by_type_and_name.3 b/man/find_key_by_type_and_name.3
index fc59a68..2d0f13d 100644
--- a/man/find_key_by_type_and_name.3
+++ b/man/find_key_by_type_and_name.3
@@ -57,5 +57,8 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
+.BR request_key (2),
 .BR keyctl (3),
-.BR request_key (3)
+.BR keyrings (7)
diff --git a/man/key.dns_resolver.8 b/man/key.dns_resolver.8
index 78523be..0529294 100644
--- a/man/key.dns_resolver.8
+++ b/man/key.dns_resolver.8
@@ -27,4 +27,8 @@
 .SH ERRORS
 All errors will be logged to the syslog.
 .SH SEE ALSO
-\fBrequest-key\fR(8), \fBrequest-key.conf\fR(5)
+.ad l
+.nh
+.BR request\-key.conf (5),
+.BR keyrings (7),
+.BR request\-key (8)
diff --git a/man/keyctl.1 b/man/keyctl.1
index 56b29ce..e7ce451 100644
--- a/man/keyctl.1
+++ b/man/keyctl.1
@@ -90,6 +90,8 @@
 \fBkeyctl\fR purge \-s <type> <desc>
 .br
 \fBkeyctl\fR get_persistent <keyring> [<uid>]
+.br
+\fBkeyctl\fR dh_compute <private> <prime> <base>
 .SH DESCRIPTION
 This program is used to control the key management facility in various ways
 using a variety of subcommands.
@@ -745,6 +747,31 @@
 If a UID other than the process's real or effective UIDs is specified, then an
 error will be given if the process does not have the CAP_SETUID capability.
 .P
+(*) \fBCompute a Diffie-Hellman shared secret or public key\fR
+.P
+\fBkeyctl\fR dh_compute <private> <prime> <base>
+.P
+This command computes either a Diffie-Hellman shared secret or the
+public key corresponding to the provided private key using the
+payloads of three keys. The computation is:
+.IP
+base ^ private (mod prime)
+.P
+The three inputs must be user keys with read permission. If the
+provided base key contains the shared generator value, the public key
+will be computed.  If the provided base key contains the remote public
+key value, the shared secret will be computed.
+.P
+The result is printed to stdout as a hex dump.
+.P
+.RS
+testbox>keyctl dh_compute $1 $2 $3
+.br
+8 bytes of data in result:
+.br
+00010203 04050607
+.RE
+.P
 .SH ERRORS
 .P
 There are a number of common errors returned by this program:
@@ -758,6 +785,11 @@
 "Key has expired" - an expired key was accessed.
 .P
 "Permission denied" - permission was denied by a UID/GID/mask combination.
+.P
 
 .SH SEE ALSO
-\fBkeyctl\fR(1), \fBrequest-key.conf\fR(5)
+.ad l
+.nh
+.BR keyctl (1),
+.BR request\-key.conf (5),
+.BR keyrings (7)
diff --git a/man/keyctl.3 b/man/keyctl.3
index 440c270..af2663b 100644
--- a/man/keyctl.3
+++ b/man/keyctl.3
@@ -43,6 +43,10 @@
 .br
 .BR keyctl_describe_alloc (3)
 .br
+.BR keyctl_dh_compute (3)
+.br
+.BR keyctl_dh_compute_alloc (3)
+.br
 .BR keyctl_get_keyring_ID (3)
 .br
 .BR keyctl_get_persistent (3)
@@ -93,14 +97,11 @@
 .BR recursive_session_key_scan (3)
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_chown.3 b/man/keyctl_chown.3
index 902fb65..0836e25 100644
--- a/man/keyctl_chown.3
+++ b/man/keyctl_chown.3
@@ -75,16 +75,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_clear.3 b/man/keyctl_clear.3
index be446a3..2b6bfa1 100644
--- a/man/keyctl_clear.3
+++ b/man/keyctl_clear.3
@@ -60,17 +60,13 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
 
diff --git a/man/keyctl_describe.3 b/man/keyctl_describe.3
index 904720a..5e4881e 100644
--- a/man/keyctl_describe.3
+++ b/man/keyctl_describe.3
@@ -97,16 +97,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_dh_compute.3 b/man/keyctl_dh_compute.3
new file mode 100644
index 0000000..9b1e6fe
--- /dev/null
+++ b/man/keyctl_dh_compute.3
@@ -0,0 +1,109 @@
+.\"
+.\" Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
+.\" Copyright (C) 2016 Intel Corporation. All rights reserved.
+.\"
+.\" 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.
+.\"
+.TH KEYCTL_DH_COMPUTE 3 "07 Apr 2016" Linux "Linux Key Management Calls"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH NAME
+keyctl_dh_compute \- Compute a Diffie-Hellman shared secret or public key
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SYNOPSIS
+.nf
+.B #include <keyutils.h>
+.sp
+.BI "long keyctl_dh_compute(key_serial_t " private ", key_serial_t " prime ,
+.BI "key_serial_t " base ", char *" buffer ", size_t " buflen ");"
+.sp
+.BI "long keyctl_dh_compute_alloc(key_serial_t " private,
+.BI "key_serial_t " prime ", key_serial_t " base ", void **" _buffer ");"
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH DESCRIPTION
+.BR keyctl_dh_compute ()
+computes a Diffie-Hellman public key or shared secret.  That computation is:
+.IP
+.I base
+^
+.I private
+( mod
+.I prime
+)
+.P
+When
+.I base
+is a key containing the shared generator value, the remote public key is
+computed.  When
+.I base
+is a key containing the remote public key, the shared secret is computed.
+.P
+.IR base ", " private ", and " prime
+must all refer to
+.BR user -type
+keys containing the parameters for the computation.  Each of these keys must
+grant the caller
+.B read
+permission in order for them to be used.
+.P
+.I buffer
+and
+.I buflen
+specify the buffer into which the computed result will be placed.
+.I buflen
+may be zero, in which case the buffer is not used and the minimum buffer length
+is fetched.
+.P
+.BR keyctl_dh_compute_alloc ()
+is similar to
+.BR keyctl_dh_compute ()
+except that it allocates a buffer big enough to hold the payload data and
+places the data in it.  If successful, a pointer to the buffer is placed in
+.IR *_buffer .
+The caller must free the buffer.
+.P
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH RETURN VALUE
+On success
+.BR keyctl_dh_compute ()
+returns the amount of data placed into the buffer when
+.I buflen
+is non-zero.  When
+.I buflen
+is zero, the minimum buffer length to hold the data is returned.
+.P
+On success
+.BR keyctl_dh_compute_alloc ()
+returns the amount of data in the buffer.
+.P
+On error, both functions set errno to an appropriate code and return the value
+.BR -1 .
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH ERRORS
+.TP
+.B ENOKEY
+One of the keys specified is invalid or not readable.
+.TP
+.B EINVAL
+The buffer pointer is invalid or buflen is too small.
+.TP
+.B EOPNOTSUPP
+One of the keys was not a valid user key.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH LINKING
+This is a library function that can be found in
+.IR libkeyutils .
+When linking,
+.B -lkeyutils
+should be specified to the linker.
+.\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+.SH SEE ALSO
+.BR keyctl (1),
+.br
+.BR keyctl (2),
+.br
+.BR keyctl (3),
+.br
+.BR keyutils (7)
diff --git a/man/keyctl_get_keyring_ID.3 b/man/keyctl_get_keyring_ID.3
index 74d6f18..bc8dd56 100644
--- a/man/keyctl_get_keyring_ID.3
+++ b/man/keyctl_get_keyring_ID.3
@@ -83,16 +83,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_get_persistent.3 b/man/keyctl_get_persistent.3
index 59077df..35c7b06 100644
--- a/man/keyctl_get_persistent.3
+++ b/man/keyctl_get_persistent.3
@@ -100,18 +100,13 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR persistent-keyring (7),
-.br
+.BR keyrings (7),
 .BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR persistent\-keyring (7),
diff --git a/man/keyctl_get_security.3 b/man/keyctl_get_security.3
index 49bda40..f99aa61 100644
--- a/man/keyctl_get_security.3
+++ b/man/keyctl_get_security.3
@@ -87,16 +87,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_instantiate.3 b/man/keyctl_instantiate.3
index 18c371f..8fe9b64 100644
--- a/man/keyctl_instantiate.3
+++ b/man/keyctl_instantiate.3
@@ -179,18 +179,13 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR request-key (8),
-.br
+.BR keyrings (7),
 .BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR request\-key (8)
diff --git a/man/keyctl_invalidate.3 b/man/keyctl_invalidate.3
index 86abe48..9545abe 100644
--- a/man/keyctl_invalidate.3
+++ b/man/keyctl_invalidate.3
@@ -63,16 +63,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_join_session_keyring.3 b/man/keyctl_join_session_keyring.3
index 2071fbd..d7ec4b4 100644
--- a/man/keyctl_join_session_keyring.3
+++ b/man/keyctl_join_session_keyring.3
@@ -69,20 +69,14 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR session-keyring (7),
-.br
-.BR user-session-keyring (7),
-.br
+.BR keyrings (7),
 .BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR session\-keyring (7),
+.BR user\-session-keyring (7)
diff --git a/man/keyctl_link.3 b/man/keyctl_link.3
index c73c4ef..6dbbc04 100644
--- a/man/keyctl_link.3
+++ b/man/keyctl_link.3
@@ -95,17 +95,13 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
 
diff --git a/man/keyctl_read.3 b/man/keyctl_read.3
index fa9485f..4411818 100644
--- a/man/keyctl_read.3
+++ b/man/keyctl_read.3
@@ -99,16 +99,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_revoke.3 b/man/keyctl_revoke.3
index 1551849..3220e10 100644
--- a/man/keyctl_revoke.3
+++ b/man/keyctl_revoke.3
@@ -60,16 +60,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_search.3 b/man/keyctl_search.3
index fb44c25..cc57f66 100644
--- a/man/keyctl_search.3
+++ b/man/keyctl_search.3
@@ -125,16 +125,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_session_to_parent.3 b/man/keyctl_session_to_parent.3
index 5b15ae5..84657e6 100644
--- a/man/keyctl_session_to_parent.3
+++ b/man/keyctl_session_to_parent.3
@@ -62,20 +62,14 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR session-keyring (7),
-.br
-.BR user-session-keyring (7),
-.br
+.BR keyrings (7),
 .BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR session\-keyring (7),
+.BR user\-session-keyring (7)
diff --git a/man/keyctl_set_reqkey_keyring.3 b/man/keyctl_set_reqkey_keyring.3
index c5f41e9..b4a8013 100644
--- a/man/keyctl_set_reqkey_keyring.3
+++ b/man/keyctl_set_reqkey_keyring.3
@@ -85,18 +85,13 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR request-key (8),
-.br
 .BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR request\-key (8)
diff --git a/man/keyctl_set_timeout.3 b/man/keyctl_set_timeout.3
index 91cc92f..523ed90 100644
--- a/man/keyctl_set_timeout.3
+++ b/man/keyctl_set_timeout.3
@@ -68,16 +68,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_setperm.3 b/man/keyctl_setperm.3
index 3bb9707..e51047a 100644
--- a/man/keyctl_setperm.3
+++ b/man/keyctl_setperm.3
@@ -117,16 +117,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyctl_update.3 b/man/keyctl_update.3
index d9575de..c971d94 100644
--- a/man/keyctl_update.3
+++ b/man/keyctl_update.3
@@ -83,16 +83,12 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (1),
-.br
 .BR add_key (2),
-.br
 .BR keyctl (2),
-.br
 .BR request_key (2),
-.br
 .BR keyctl (3),
-.br
-.BR keyutils (7),
-.br
-.BR keyrings (7)
+.BR keyrings (7),
+.BR keyutils (7)
diff --git a/man/keyutils.7 b/man/keyutils.7
index b49e21e..5257a6c 100644
--- a/man/keyutils.7
+++ b/man/keyutils.7
@@ -92,19 +92,15 @@
 manual pages for more information.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
+.BR keyctl (1),
+.BR keyctl (3),
 .BR keyrings (7),
-.br
-.BR pam_keyinit (8),
-.br
-.BR process-keyring (7),
-.br
-.BR session-keyring (7),
-.br
-.BR thread-keyring (7),
-.br
-.BR user-keyring (7),
-.br
-.BR user-session-keyring (7),
-.br
-.BR persistent-keyring (7)
-
+.BR persistent\-keyring (7),
+.BR process\-keyring (7),
+.BR session\-keyring (7),
+.BR thread\-keyring (7),
+.BR user\-keyring (7),
+.BR user\-session-keyring (7),
+.BR pam_keyinit (8)
diff --git a/man/recursive_key_scan.3 b/man/recursive_key_scan.3
index 7d69d5d..4ec6399 100644
--- a/man/recursive_key_scan.3
+++ b/man/recursive_key_scan.3
@@ -83,5 +83,8 @@
 should be specified to the linker.
 .\"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
 .SH SEE ALSO
+.ad l
+.nh
 .BR keyctl (3),
-.BR keyctl_describe_alloc (3)
+.BR keyctl_describe_alloc (3),
+.BR keyrings (7)
diff --git a/man/request-key.8 b/man/request-key.8
index 8d4a880..5867978 100644
--- a/man/request-key.8
+++ b/man/request-key.8
@@ -31,4 +31,8 @@
 .ul 0
 Keytype specific configuration file.
 .SH SEE ALSO
-\fBkeyctl\fR(1), \fBrequest-key.conf\fR(5)
+.ad l
+.nh
+.BR keyctl (1),
+.BR request\-key.conf (5),
+.BR keyrings (7)
diff --git a/tests/keyctl/dh_compute/bad-args/runtest.sh b/tests/keyctl/dh_compute/bad-args/runtest.sh
new file mode 100644
index 0000000..7e8828b
--- /dev/null
+++ b/tests/keyctl/dh_compute/bad-args/runtest.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+if [ $have_dh_compute = 0 ]
+then
+    toolbox_skip_test $TEST "SKIPPING DUE TO LACK OF DIFFIE-HELLMAN"
+    exit 0
+fi
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# Prime, generator, and key values created with:
+#   openssl dhparam 2048 -check -out dh.pem
+#   openssl genpkey -paramfile dh.pem -text
+prime="\x00\xb6\x89\x4d\x8f\xf7\xaf\x56\xd4\x46\xc9\x50\xc7\xe9\x1d"
+prime+="\x29\x8a\x07\x8d\xae\xa7\x79\x66\xf1\x1f\xc1\x6f\x22\x92\x11"
+prime+="\x73\x7f\x1f\x39\xce\xf3\xda\xd7\x87\x2a\x53\x8f\x6c\x8f\x9a"
+prime+="\x27\x6a\x7c\xf7\x7b\xb2\xd6\x3a\x87\x2a\x4d\xb9\xed\x12\xae"
+prime+="\x0f\x1c\x69\xaf\x9b\xf2\xf2\xe3\x69\x1d\x36\x15\xa1\xd7\xd5"
+prime+="\x77\xa8\x7d\x1c\xb4\xab\xa0\x49\x4b\xae\x0c\x24\x9b\x0c\xce"
+prime+="\xef\x6b\x7a\xb9\xa7\xbe\x70\xb5\xb4\x5e\x4c\xf7\xcb\x71\xad"
+prime+="\x8f\xeb\x7a\x4d\x6c\x7c\xcb\x96\xd5\x29\x8f\x0f\xee\xb4\x78"
+prime+="\x77\x60\x5e\x80\xa0\x33\x86\x91\xe3\x58\x62\xf0\xf4\xcb\xb2"
+prime+="\x09\xe1\x7d\xd9\xfe\xbc\xce\x4c\x21\x57\x70\x06\xce\xb1\x15"
+prime+="\x7b\x18\x15\x92\xd2\xf7\x84\xba\x44\xe0\x06\xc3\x14\xdf\x53"
+prime+="\x06\xbd\xbb\x17\xa0\x10\xb3\x66\x0d\x47\x93\x56\xd8\xd5\x2c"
+prime+="\x5a\xf0\x14\x53\x6c\x20\x89\x7e\x76\x53\x21\x8e\x2c\x7a\x65"
+prime+="\x0a\x73\xdc\x27\x58\x45\x98\xde\x92\xde\x5c\x62\x70\x67\x71"
+prime+="\xfa\x2d\x67\xf6\x25\x44\x1d\x91\x1c\xa0\x3f\x21\x49\xb6\xd4"
+prime+="\xc7\x6b\x5e\xcd\x98\x96\xe9\xd7\x99\xa3\xa5\x00\xec\xec\xc5"
+prime+="\x19\xe3\x1b\x71\x15\x4d\x7b\x36\x1b\xd0\xdd\x15\xf7\xce\x8d"
+prime+="\xfc\x63"
+
+generator="\x02"
+
+private="\x40\x94\x9d\xa2\xca\x2b\x7c\x35\x3d\xe3\x8f\xef\xb0\x6d\xdd"
+private+="\x0d\x67\x47\x9a\x63\x61\xc8\x9e\x77\xb9\x80\xd2\x48\x6c\x4d"
+private+="\x31\x97\x1e\xb8\x8f\x65\x72\x06\x99\x73\xe3\xae\x5a\x43\xce"
+private+="\x76\xbc\xcb\x35\xea\x05\xac\x65\x38\xeb\x0e\xa6\xad\xee\x49"
+private+="\x37\x60\x04\x35\xdd\x79\x40\x88\x5d\x2e\x3f\x78\xc7\x28\x08"
+private+="\x34\xf8\x78\xd3\xd5\x50\xcc\x93\x05\x33\x0b\xb8\xf0\x20\x85"
+private+="\xee\x6c\x23\x0d\x42\xd8\x4e\xb6\x7a\x24\x5b\x92\x81\x7f\xd1"
+private+="\x54\xbc\xb1\x39\x4a\x28\x9d\x11\xaf\xb5\xa1\xe5\x0e\x13\x95"
+private+="\x09\x08\xaf\x70\x75\x67\x04\xe9\xbf\x03\xdf\xf0\xe5\xd4\x90"
+private+="\x74\x38\x41\xc5\x34\xcb\x7e\x2c\xf4\xb9\xf0\x49\x3a\x73\x0b"
+private+="\x0d\x71\x09\x6a\x16\xbd\xc0\xe8\x52\xf1\x75\x75\x51\x34\xb2"
+private+="\xb4\x11\x12\x28\x0a\x88\x21\x27\x28\xaf\xbe\x16\xd4\x17\xf3"
+private+="\x18\x93\xcb\xe4\x42\xe0\x6d\x21\x2d\x8e\xfe\x22\x7a\xa0\x03"
+private+="\x9a\x65\xce\x99\x81\x07\xfa\xe2\x78\x51\x1c\x6b\xf4\xd5\x99"
+private+="\x32\x53\x4a\xe9\xfc\x39\xdb\x80\x63\x51\x63\xc0\x54\x66\x57"
+private+="\x50\x08\x66\xd5\x46\x1c\x5f\xa3\x54\x02\x38\x32\x4a\x29\xf3"
+private+="\x16\xe0\x68\xf3\xba\x17\x37\xd0\x42\xcb\x51\xa8\x97\x1b\xc7"
+private+="\xa2"
+
+pcreate_key "-e $prime" user dh:prime @s
+expect_keyid primeid
+
+pcreate_key "-e $generator" user dh:generator @s
+expect_keyid generatorid
+
+pcreate_key "-e $private" user dh:private @s
+expect_keyid privateid
+
+pcreate_key "-e \x00" logon dh:logon @s
+expect_keyid logonid
+
+marker "CHECK WRONG KEY TYPE"
+dh_compute --fail $privateid $primeid $logonid
+expect_error ENOKEY
+dh_compute --fail $privateid $primeid @s
+expect_error EOPNOTSUPP
+
+marker "CHECK MISSING KEY"
+dh_compute --fail $privateid $primeid 0
+expect_error ENOKEY
+unlink_key --wait $generatorid @s
+dh_compute --fail $privateid $primeid $generatorid
+expect_error ENOKEY
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/dh_compute/noargs/runtest.sh b/tests/keyctl/dh_compute/noargs/runtest.sh
new file mode 100644
index 0000000..e761f6b
--- /dev/null
+++ b/tests/keyctl/dh_compute/noargs/runtest.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+if [ $have_dh_compute = 0 ]
+then
+    toolbox_skip_test $TEST "SKIPPING DUE TO LACK OF DIFFIE-HELLMAN"
+    exit 0
+fi
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+marker "NO ARGS"
+expect_args_error keyctl dh_compute
+
+marker "TWO ARGS"
+expect_args_error keyctl dh_compute 0 0
+
+marker "FOUR ARGS"
+expect_args_error keyctl dh_compute 0 0 0 0
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/keyctl/dh_compute/valid/runtest.sh b/tests/keyctl/dh_compute/valid/runtest.sh
new file mode 100644
index 0000000..f2aace6
--- /dev/null
+++ b/tests/keyctl/dh_compute/valid/runtest.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+
+. ../../../prepare.inc.sh
+. ../../../toolbox.inc.sh
+
+
+# ---- do the actual testing ----
+
+if [ $have_dh_compute = 0 ]
+then
+    toolbox_skip_test $TEST "SKIPPING DUE TO LACK OF DIFFIE-HELLMAN"
+    exit 0
+fi
+
+result=PASS
+echo "++++ BEGINNING TEST" >$OUTPUTFILE
+
+# Prime, generator, and key values created with:
+#   openssl dhparam 2048 -check -out dh.pem
+#   openssl genpkey -paramfile dh.pem -text
+prime="\x00\xb6\x89\x4d\x8f\xf7\xaf\x56\xd4\x46\xc9\x50\xc7\xe9\x1d"
+prime+="\x29\x8a\x07\x8d\xae\xa7\x79\x66\xf1\x1f\xc1\x6f\x22\x92\x11"
+prime+="\x73\x7f\x1f\x39\xce\xf3\xda\xd7\x87\x2a\x53\x8f\x6c\x8f\x9a"
+prime+="\x27\x6a\x7c\xf7\x7b\xb2\xd6\x3a\x87\x2a\x4d\xb9\xed\x12\xae"
+prime+="\x0f\x1c\x69\xaf\x9b\xf2\xf2\xe3\x69\x1d\x36\x15\xa1\xd7\xd5"
+prime+="\x77\xa8\x7d\x1c\xb4\xab\xa0\x49\x4b\xae\x0c\x24\x9b\x0c\xce"
+prime+="\xef\x6b\x7a\xb9\xa7\xbe\x70\xb5\xb4\x5e\x4c\xf7\xcb\x71\xad"
+prime+="\x8f\xeb\x7a\x4d\x6c\x7c\xcb\x96\xd5\x29\x8f\x0f\xee\xb4\x78"
+prime+="\x77\x60\x5e\x80\xa0\x33\x86\x91\xe3\x58\x62\xf0\xf4\xcb\xb2"
+prime+="\x09\xe1\x7d\xd9\xfe\xbc\xce\x4c\x21\x57\x70\x06\xce\xb1\x15"
+prime+="\x7b\x18\x15\x92\xd2\xf7\x84\xba\x44\xe0\x06\xc3\x14\xdf\x53"
+prime+="\x06\xbd\xbb\x17\xa0\x10\xb3\x66\x0d\x47\x93\x56\xd8\xd5\x2c"
+prime+="\x5a\xf0\x14\x53\x6c\x20\x89\x7e\x76\x53\x21\x8e\x2c\x7a\x65"
+prime+="\x0a\x73\xdc\x27\x58\x45\x98\xde\x92\xde\x5c\x62\x70\x67\x71"
+prime+="\xfa\x2d\x67\xf6\x25\x44\x1d\x91\x1c\xa0\x3f\x21\x49\xb6\xd4"
+prime+="\xc7\x6b\x5e\xcd\x98\x96\xe9\xd7\x99\xa3\xa5\x00\xec\xec\xc5"
+prime+="\x19\xe3\x1b\x71\x15\x4d\x7b\x36\x1b\xd0\xdd\x15\xf7\xce\x8d"
+prime+="\xfc\x63"
+
+generator="\x02"
+
+private="\x40\x94\x9d\xa2\xca\x2b\x7c\x35\x3d\xe3\x8f\xef\xb0\x6d\xdd"
+private+="\x0d\x67\x47\x9a\x63\x61\xc8\x9e\x77\xb9\x80\xd2\x48\x6c\x4d"
+private+="\x31\x97\x1e\xb8\x8f\x65\x72\x06\x99\x73\xe3\xae\x5a\x43\xce"
+private+="\x76\xbc\xcb\x35\xea\x05\xac\x65\x38\xeb\x0e\xa6\xad\xee\x49"
+private+="\x37\x60\x04\x35\xdd\x79\x40\x88\x5d\x2e\x3f\x78\xc7\x28\x08"
+private+="\x34\xf8\x78\xd3\xd5\x50\xcc\x93\x05\x33\x0b\xb8\xf0\x20\x85"
+private+="\xee\x6c\x23\x0d\x42\xd8\x4e\xb6\x7a\x24\x5b\x92\x81\x7f\xd1"
+private+="\x54\xbc\xb1\x39\x4a\x28\x9d\x11\xaf\xb5\xa1\xe5\x0e\x13\x95"
+private+="\x09\x08\xaf\x70\x75\x67\x04\xe9\xbf\x03\xdf\xf0\xe5\xd4\x90"
+private+="\x74\x38\x41\xc5\x34\xcb\x7e\x2c\xf4\xb9\xf0\x49\x3a\x73\x0b"
+private+="\x0d\x71\x09\x6a\x16\xbd\xc0\xe8\x52\xf1\x75\x75\x51\x34\xb2"
+private+="\xb4\x11\x12\x28\x0a\x88\x21\x27\x28\xaf\xbe\x16\xd4\x17\xf3"
+private+="\x18\x93\xcb\xe4\x42\xe0\x6d\x21\x2d\x8e\xfe\x22\x7a\xa0\x03"
+private+="\x9a\x65\xce\x99\x81\x07\xfa\xe2\x78\x51\x1c\x6b\xf4\xd5\x99"
+private+="\x32\x53\x4a\xe9\xfc\x39\xdb\x80\x63\x51\x63\xc0\x54\x66\x57"
+private+="\x50\x08\x66\xd5\x46\x1c\x5f\xa3\x54\x02\x38\x32\x4a\x29\xf3"
+private+="\x16\xe0\x68\xf3\xba\x17\x37\xd0\x42\xcb\x51\xa8\x97\x1b\xc7"
+private+="\xa2"
+
+read -d '' public <<"EOF"
+a4cf1f93 95fce03f d02aaece da1f86bd d8d77b69 29039fcc bd138c98 2483bf9c
+7e4406c1 4f3cea24 6cafb29e 95095d0c 6768f13b 31babb24 6c590d92 6c343e69
+59dbd47f 65982a3b b1baa7a3 05a72054 89b6cd0d 78397962 fc834fc9 3ec0517e
+c218396f 9cff860e 29078aee 6b8598b6 79325014 bb84597d f031e149 edbe1c5a
+2a55fe4e bbc64a52 6da59e71 1c7ae5e0 954ba23b 9d58c423 17d84841 815708c8
+b9059987 48773eac 2244b286 cd118277 48b7ed3a 5af5cc0f 8f254190 5e16f998
+a328e894 acc343f4 66a95281 86cea6a3 93eb4fee f83c0e2e f4a00ce6 fcc9ef81
+cc4624d5 ba659411 d1ba7b5f 14a3e286 d42e6ac8 afa9f846 41cb7cb5 66965725
+EOF
+
+pcreate_key "-e $prime" user dh:prime @s
+expect_keyid primeid
+
+pcreate_key "-e $generator" user dh:generator @s
+expect_keyid generatorid
+
+pcreate_key "-e $private" user dh:private @s
+expect_keyid privateid
+
+marker "COMPUTE DH PUBLIC KEY"
+dh_compute $privateid $primeid $generatorid
+expect_multiline payload "$public"
+
+echo "++++ FINISHED TEST: $result" >>$OUTPUTFILE
+
+# --- then report the results in the database ---
+toolbox_report_result $TEST $result
diff --git a/tests/prepare.inc.sh b/tests/prepare.inc.sh
index a2793d4..9a663c0 100644
--- a/tests/prepare.inc.sh
+++ b/tests/prepare.inc.sh
@@ -93,6 +93,15 @@
 fi
 
 #
+# Work out whether Diffie-Hellman is supported by the kernel
+#
+have_dh_compute=0
+if keyutils_at_or_later_than 1.5.10 && kernel_at_or_later_than 4.7-rc1
+then
+    have_dh_compute=1
+fi
+
+#
 # Check if skipping of tests requiring root was requested
 #
 skip_root_required=0
diff --git a/tests/toolbox.inc.sh b/tests/toolbox.inc.sh
index 5ac23ff..7f19a02 100644
--- a/tests/toolbox.inc.sh
+++ b/tests/toolbox.inc.sh
@@ -672,6 +672,25 @@
 
 ###############################################################################
 #
+# extract multiline output from the log file
+#
+###############################################################################
+function expect_multiline ()
+{
+    my_varname=$1
+    my_linecount="`echo \"$2\" | wc -l`"
+
+    my_payload=$(tail -$my_linecount $OUTPUTFILE)
+    eval $my_varname="\"$my_payload\""
+
+    if [ $# != 2 -o "x$my_payload" != "x$2" ]
+    then
+	failed
+    fi
+}
+
+###############################################################################
+#
 # revoke a key
 #
 ###############################################################################
@@ -1065,6 +1084,28 @@
 
 ###############################################################################
 #
+# Do a DH computation
+#
+###############################################################################
+function dh_compute ()
+{
+    my_exitval=0
+    if [ "x$1" = "x--fail" ]
+    then
+	my_exitval=1
+	shift
+    fi
+
+    echo keyctl dh_compute $@ >>$OUTPUTFILE
+    keyctl dh_compute $@ >>$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 5f07463..2bfed13 100644
--- a/version.lds
+++ b/version.lds
@@ -23,7 +23,7 @@
 	keyctl_set_reqkey_keyring;
 	keyctl_unlink;
 	keyctl_update;
-	 
+
 };
 
 KEYUTILS_1.0 {
@@ -61,3 +61,10 @@
 	find_key_by_type_and_desc;
 
 } KEYUTILS_1.4;
+
+KEYUTILS_1.6 {
+	/* management functions */
+	keyctl_dh_compute;
+	keyctl_dh_compute_alloc;
+
+} KEYUTILS_1.5;