diff --git a/README.md b/README.md
index 26784f8..fe72a91 100644
--- a/README.md
+++ b/README.md
@@ -65,7 +65,8 @@ following command:
 		netlabel_tools \
 		iptables \
 		lksctp-tools-devel \
-		attr
+		attr \
+		keyutils-libs-devel
 
 The testsuite requires a pre-existing base policy configuration of SELinux,
 using either the old example policy or the reference policy as the baseline.
diff --git a/defconfig b/defconfig
index d7f0ea5..c00e291 100644
--- a/defconfig
+++ b/defconfig
@@ -62,3 +62,11 @@ CONFIG_ANDROID_BINDER_IPC=y
 # This will configure the Dynamically Allocated Binder Devices added
 # to 5.0+ kernels:
 CONFIG_ANDROID_BINDERFS=y
+
+# Key implementations.
+# These are enabled to test the key and key_socket controls in
+# tests/keys; they are not required for SELinux operation itself.
+CONFIG_KEYS=y
+CONFIG_KEYS_COMPAT=y
+CONFIG_KEY_DH_OPERATIONS=y
+CONFIG_NET_KEY=m
diff --git a/policy/Makefile b/policy/Makefile
index 305b572..9258a93 100644
--- a/policy/Makefile
+++ b/policy/Makefile
@@ -71,6 +71,10 @@ ifeq ($(shell grep -q corenet_sctp_bind_all_nodes $(POLDEV)/include/kernel/coren
 TARGETS += test_sctp.te
 endif
 
+ifeq ($(shell grep -q key_socket $(POLDEV)/include/support/all_perms.spt && echo true),true)
+TARGETS += test_keys.te
+endif
+
 ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
 TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te, $(TARGETS))
 endif
diff --git a/policy/test_keys.te b/policy/test_keys.te
new file mode 100644
index 0000000..9c65ec8
--- /dev/null
+++ b/policy/test_keys.te
@@ -0,0 +1,161 @@
+#
+################# KEY selinux-testsuite policy module ######################
+#
+attribute keydomain;
+
+#
+############################## Define Macro ################################
+#
+# Do not use domain_type() macro as it has allow 'key { link search }'
+# in base module so 'allow domain self:key ~{ link search };' will not work
+# here. Add these instead to allow key perms to be controlled by this module:
+#
+define(`key_domain_type',`
+	allow $1 proc_t:dir { search };
+	allow $1 proc_t:lnk_file { read };
+	allow $1 self:dir { search };
+	allow $1 self:file { open read write };
+')
+
+#
+####################### Main key class tests #####################
+#
+type test_key_t;
+key_domain_type(test_key_t)
+unconfined_runs_test(test_key_t)
+typeattribute test_key_t testdomain;
+typeattribute test_key_t keydomain;
+
+allow test_key_t self:process { setkeycreate };
+allow test_key_t self:key { create write search read view link setattr };
+
+# Set new context on a keyring:
+type test_newcon_key_t;
+key_domain_type(test_newcon_key_t)
+unconfined_runs_test(test_newcon_key_t)
+typeattribute test_newcon_key_t testdomain;
+typeattribute test_newcon_key_t keydomain;
+
+allow test_key_t test_newcon_key_t:key { create write search view };
+
+################# Deny process { setkeycreate } #######################
+type test_no_setkeycreate_t;
+key_domain_type(test_no_setkeycreate_t)
+unconfined_runs_test(test_no_setkeycreate_t)
+typeattribute test_no_setkeycreate_t testdomain;
+typeattribute test_no_setkeycreate_t keydomain;
+
+###################### Deny key { create } ###########################
+type test_key_no_create_t;
+key_domain_type(test_key_no_create_t)
+unconfined_runs_test(test_key_no_create_t)
+typeattribute test_key_no_create_t testdomain;
+typeattribute test_key_no_create_t keydomain;
+
+allow test_key_no_create_t self:process { setkeycreate };
+allow test_key_no_create_t self:key { write search read view link setattr };
+
+###################### Deny key { write } ###########################
+type test_key_no_write_t;
+key_domain_type(test_key_no_write_t)
+unconfined_runs_test(test_key_no_write_t)
+typeattribute test_key_no_write_t testdomain;
+typeattribute test_key_no_write_t keydomain;
+
+allow test_key_no_write_t self:process { setkeycreate };
+allow test_key_no_write_t self:key { create search read view link setattr };
+
+###################### Deny key { search } ###########################
+type test_key_no_search_t;
+key_domain_type(test_key_no_search_t)
+unconfined_runs_test(test_key_no_search_t)
+typeattribute test_key_no_search_t testdomain;
+typeattribute test_key_no_search_t keydomain;
+
+allow test_key_no_search_t self:process { setkeycreate };
+allow test_key_no_search_t self:key { create write read view link setattr };
+
+###################### Deny key { view } ###########################
+type test_key_no_view_t;
+key_domain_type(test_key_no_view_t)
+unconfined_runs_test(test_key_no_view_t)
+typeattribute test_key_no_view_t testdomain;
+typeattribute test_key_no_view_t keydomain;
+
+allow test_key_no_view_t self:process { setkeycreate };
+allow test_key_no_view_t self:key { create write search read link setattr };
+
+###################### Deny key { read } ###########################
+type test_key_no_read_t;
+key_domain_type(test_key_no_read_t)
+unconfined_runs_test(test_key_no_read_t)
+typeattribute test_key_no_read_t testdomain;
+typeattribute test_key_no_read_t keydomain;
+
+allow test_key_no_read_t self:process { setkeycreate };
+allow test_key_no_read_t self:key { create write search view link setattr };
+
+###################### Deny key { link } ###########################
+type test_key_no_link_t;
+key_domain_type(test_key_no_link_t)
+unconfined_runs_test(test_key_no_link_t)
+typeattribute test_key_no_link_t testdomain;
+typeattribute test_key_no_link_t keydomain;
+
+allow test_key_no_link_t self:process { setkeycreate };
+allow test_key_no_link_t self:key { create write search read view setattr };
+
+###################### Deny key { setattr } ###########################
+type test_key_no_setattr_t;
+key_domain_type(test_key_no_setattr_t)
+unconfined_runs_test(test_key_no_setattr_t)
+typeattribute test_key_no_setattr_t testdomain;
+typeattribute test_key_no_setattr_t keydomain;
+
+allow test_key_no_setattr_t self:process { setkeycreate };
+allow test_key_no_setattr_t self:key { create write search read view link };
+
+#
+######################## Test key_socket class ###########################
+#
+type test_key_sock_t;
+domain_type(test_key_sock_t)
+unconfined_runs_test(test_key_sock_t)
+typeattribute test_key_sock_t testdomain;
+typeattribute test_key_sock_t keydomain;
+
+# key_socket rules:
+allow test_key_sock_t self:rawip_socket { create };
+allow test_key_sock_t self:capability { net_admin };
+allow test_key_sock_t self:key_socket { create write };
+# For CONFIG_NET_KEY=m
+allow test_key_sock_t kernel_t:system { module_request };
+
+################## Deny capability { net_admin } ##########################
+type test_key_sock_no_net_admin_t;
+domain_type(test_key_sock_no_net_admin_t)
+unconfined_runs_test(test_key_sock_no_net_admin_t)
+typeattribute test_key_sock_no_net_admin_t testdomain;
+typeattribute test_key_sock_no_net_admin_t keydomain;
+
+# key_socket rules:
+allow test_key_sock_no_net_admin_t self:rawip_socket { create };
+allow test_key_sock_no_net_admin_t self:key_socket { create write };
+
+####################### Deny key_socket { create } ##########################
+type test_key_sock_no_create_t;
+domain_type(test_key_sock_no_create_t)
+unconfined_runs_test(test_key_sock_no_create_t)
+typeattribute test_key_sock_no_create_t testdomain;
+typeattribute test_key_sock_no_create_t keydomain;
+
+# key_socket rules:
+allow test_key_sock_no_create_t self:rawip_socket { create };
+allow test_key_sock_no_create_t self:capability { net_admin };
+allow test_key_sock_no_create_t self:key_socket { write };
+
+#
+########### Allow these domains to be entered from sysadm domain ############
+#
+miscfiles_domain_entry_test_files(keydomain)
+userdom_sysadm_entry_spec_domtrans_to(keydomain)
diff --git a/tests/Makefile b/tests/Makefile
index 63aa325..d1dbf38 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -42,6 +42,10 @@ ifeq ($(shell grep -q binder $(POLDEV)/include/support/all_perms.spt && test -e
 SUBDIRS += binder
 endif
 
+ifeq ($(shell grep -q key_socket $(POLDEV)/include/support/all_perms.spt && test -e $(INCLUDEDIR)/keyutils.h && echo true),true)
+SUBDIRS += keys
+endif
+
 ifeq ($(shell grep "^SELINUX_INFINIBAND_ENDPORT_TEST=" infiniband_endport/ibendport_test.conf | cut -d'=' -f 2),1)
 SUBDIRS += infiniband_endport
 endif
diff --git a/tests/keys/.gitignore b/tests/keys/.gitignore
new file mode 100644
index 0000000..4a0a48d
--- /dev/null
+++ b/tests/keys/.gitignore
@@ -0,0 +1,3 @@
+keyctl
+keyctl_relabel
+key_sock
diff --git a/tests/keys/Makefile b/tests/keys/Makefile
new file mode 100644
index 0000000..3a00df5
--- /dev/null
+++ b/tests/keys/Makefile
@@ -0,0 +1,8 @@
+TARGETS = keyctl key_sock keyctl_relabel
+
+LDLIBS += -lselinux -lkeyutils
+
+all: $(TARGETS)
+
+clean:
+	rm -f $(TARGETS)
diff --git a/tests/keys/key_sock.c b/tests/keys/key_sock.c
new file mode 100644
index 0000000..8ac1f45
--- /dev/null
+++ b/tests/keys/key_sock.c
@@ -0,0 +1,67 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <linux/pfkeyv2.h>
+#include <selinux/selinux.h>
+
+static void usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v]\n"
+		"Where:\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	char *context;
+	int opt, sock, result;
+	bool verbose = false;
+
+	while ((opt = getopt(argc, argv, "v")) != -1) {
+		switch (opt) {
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	result = getcon(&context);
+	if (result < 0) {
+		fprintf(stderr, "Failed to obtain process context\n");
+		exit(-1);
+	}
+	if (verbose)
+		printf("Process context: %s\n", context);
+
+	sock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
+	if (sock < 0) {
+		fprintf(stderr, "Failed to open PF_KEY socket: %s\n",
+			strerror(errno));
+		exit(errno);
+	}
+	if (verbose)
+		printf("Opened PF_KEY socket\n");
+
+	/* Write nothing to socket for test, expect EMSGSIZE error */
+	result = write(sock, NULL, 0);
+	if (result < 0 && errno == EMSGSIZE) {
+		result = 0;
+		if (verbose)
+			printf("Written to PF_KEY socket\n");
+	} else if (result < 0 && errno != EMSGSIZE) {
+		result = -1;
+		fprintf(stderr, "Failed write to PF_KEY socket: %s\n",
+			strerror(errno));
+	}
+
+	close(sock);
+	return result;
+}
diff --git a/tests/keys/keyctl.c b/tests/keys/keyctl.c
new file mode 100644
index 0000000..6d85be7
--- /dev/null
+++ b/tests/keys/keyctl.c
@@ -0,0 +1,241 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <keyutils.h>
+#include <selinux/selinux.h>
+
+/* This is used as the payload for each add_key() */
+static const char payload[] =
+	" -----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDN4FHsPjlJf03r9KfNt1Ma9/D6\nQDEiR/cfhZrNUPgHRrC+E4dj52VJSonPFJ6HaLlUi5pZq2t1LqPNrMfFKCNn12m+\nWw4aduBJM7u1RUPSNxrlfDAJZkdtNALOO/ds3U93hZrxOYNetzbnjILDu5JT1nbI\n4aC60SkdlCw1TxmvXwIDAQAB\n-----END PUBLIC KEY-----\n";
+
+static void usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v]\n"
+		"Where:\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, result;
+	char *context, *keycreate_con;
+	char r_con[256];
+	bool verbose = false;
+	key_serial_t retrieved, search, link, compute, newring,
+		     private, prime, base, test_key;
+	struct keyctl_dh_params params;
+
+	while ((opt = getopt(argc, argv, "v")) != -1) {
+		switch (opt) {
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	result = getcon(&context);
+	if (result < 0) {
+		fprintf(stderr, "Failed to obtain process context\n");
+		exit(1);
+	}
+	if (verbose)
+		printf("Process context: %s\n", context);
+
+	result = getkeycreatecon(&keycreate_con);
+	if (result < 0) {
+		fprintf(stderr, "Failed to obtain keycreate context\n");
+		exit(2);
+	}
+	if (verbose)
+		printf("Current keycreate context: %s\n", keycreate_con);
+	free(keycreate_con);
+
+	/* Set context requires process { setkeycreate } and key { create } */
+	result = setkeycreatecon(context);
+	if (result < 0) {
+		fprintf(stderr, "Failed setkeycreatecon(): %s\n",
+			strerror(errno));
+		exit(3);
+	}
+	if (verbose)
+		printf("Set keycreate context: %s\n", context);
+	free(context);
+
+	result = getkeycreatecon(&keycreate_con);
+	if (result < 0) {
+		fprintf(stderr, "Failed to obtain keycreate context\n");
+		exit(4);
+	}
+	if (verbose)
+		printf("New keycreate context: %s\n", keycreate_con);
+	free(keycreate_con);
+
+	/*
+	 * Add three keys as these will be required by the
+	 * keyctl(KEYCTL_DH_COMPUTE, ..) function.
+	 * These require key { create write } permissions.
+	 */
+	private = add_key("user", "private", payload, strlen(payload),
+			  KEY_SPEC_PROCESS_KEYRING);
+	if (private < 0) {
+		fprintf(stderr, "Failed add_key(private): %s\n",
+			strerror(errno));
+		exit(5);
+	}
+
+	prime = add_key("user", "prime", payload, strlen(payload),
+			KEY_SPEC_PROCESS_KEYRING);
+	if (prime < 0) {
+		fprintf(stderr, "Failed add_key(prime): %s\n",
+			strerror(errno));
+		exit(6);
+	}
+
+	base = add_key("user", "base", payload, strlen(payload),
+		       KEY_SPEC_PROCESS_KEYRING);
+	if (base < 0) {
+		fprintf(stderr, "Failed add_key(base): %s\n",
+			strerror(errno));
+		exit(7);
+	}
+
+	if (verbose) {
+		printf("Private key ID: 0x%x\n", private);
+		printf("Prime key ID:   0x%x\n", prime);
+		printf("Base key ID:    0x%x\n", base);
+	}
+
+	/* Requires key { search }. From kernel 5.3 also requires { link } */
+	retrieved = request_key("user", "private", NULL,
+				KEY_SPEC_PROCESS_KEYRING);
+	if (retrieved < 0) {
+		fprintf(stderr, "Failed to request 'private' key: %s\n",
+			strerror(errno));
+		exit(8);
+	}
+
+	/* Requires key { search } */
+	search = keyctl(KEYCTL_SEARCH, KEY_SPEC_PROCESS_KEYRING, "user",
+			"base", 0);
+	if (search < 0) {
+		fprintf(stderr, "Failed to find 'base' key: %s\n",
+			strerror(errno));
+		exit(9);
+	}
+
+	/* Requires key { view } */
+	result = keyctl(KEYCTL_GET_SECURITY, search, r_con, sizeof(r_con));
+	if (result < 0) {
+		fprintf(stderr, "Failed to obtain key context: %s\n",
+			strerror(errno));
+		exit(10);
+	}
+
+	if (verbose) {
+		printf("Requested 'private' key ID: 0x%x\n", retrieved);
+		printf("Searched 'base' key ID:     0x%x\n", search);
+		printf("Searched 'base' key context:\n\t%s\n", r_con);
+	}
+
+	/* Compute DH key, only obtain the length for test, not the key. */
+	params.priv = private;
+	params.prime = prime;
+	params.base = base;
+
+	/* Requires key { create read write } */
+	compute = keyctl(KEYCTL_DH_COMPUTE, &params, NULL, 0, 0);
+	if (compute < 0) {
+		fprintf(stderr, "Failed KEYCTL_DH_COMPUTE: %s\n",
+			strerror(errno));
+		exit(11);
+	}
+	if (verbose)
+		printf("KEYCTL_DH_COMPUTE key ID size: %d\n", compute);
+
+	/* To test key { link }, need to generate a new keyring ID first */
+	newring = add_key("keyring", "my-keyring", NULL, 0,
+			  KEY_SPEC_THREAD_KEYRING);
+	if (newring < 0) {
+		fprintf(stderr, "Failed to add new keyring: %s\n",
+			strerror(errno));
+		exit(12);
+	}
+	if (verbose)
+		printf("New keyring ID: 0x%x\n", newring);
+
+	/* Requires key { write link } */
+	link = keyctl(KEYCTL_LINK, base, newring);
+	if (link < 0) {
+		fprintf(stderr, "Failed KEYCTL_LINK: %s\n",
+			strerror(errno));
+		exit(13);
+	}
+	if (verbose)
+		printf("Link key ID:    0x%x\n", newring);
+
+	/* Requires key { setattr } */
+	link = keyctl(KEYCTL_RESTRICT_KEYRING, newring, NULL, NULL);
+	if (link < 0) {
+		fprintf(stderr, "Failed KEYCTL_RESTRICT_KEYRING: %s\n",
+			strerror(errno));
+		exit(14);
+	}
+	if (verbose)
+		printf("Restricted keyring\n");
+
+	/* Requires key { search } from 5.X key { inval } */
+	test_key = keyctl(KEYCTL_INVALIDATE, private);
+	if (test_key < 0) {
+		fprintf(stderr, "Failed KEYCTL_INVALIDATE(private): %s\n",
+			strerror(errno));
+		exit(15);
+	}
+	if (verbose)
+		printf("Invalidated 'private' key\n");
+
+	/* Requires key { write setattr } from 5.X key { revoke } */
+	test_key = keyctl(KEYCTL_REVOKE, prime);
+	if (test_key < 0) {
+		fprintf(stderr, "Failed KEYCTL_REVOKE(prime): %s\n",
+			strerror(errno));
+		exit(16);
+	}
+	if (verbose)
+		printf("Revoked 'prime' key\n");
+
+	/* Requires key { write } from 5.X key { clear } */
+	test_key = keyctl(KEYCTL_CLEAR, newring);
+	if (test_key < 0) {
+		fprintf(stderr, "Failed KEYCTL_CLEAR(newring): %s\n",
+			strerror(errno));
+		exit(17);
+	}
+	if (verbose)
+		printf("Cleared 'newring' keyring\n");
+
+	/* To test key { join }, need to join session first */
+	test_key = keyctl(KEYCTL_JOIN_SESSION_KEYRING, "user");
+	if (test_key < 0) {
+		fprintf(stderr, "Failed KEYCTL_JOIN_SESSION_KEYRING,: %s\n",
+			strerror(errno));
+		exit(18);
+	}
+	/* Requires key { link } from 5.X key { join } */
+	test_key = keyctl(KEYCTL_SESSION_TO_PARENT);
+	if (test_key < 0) {
+		fprintf(stderr, "Failed KEYCTL_SESSION_TO_PARENT: %s\n",
+			strerror(errno));
+		exit(19);
+	}
+	if (verbose)
+		printf("Joined session to parent\n");
+
+	return 0;
+}
diff --git a/tests/keys/keyctl_relabel.c b/tests/keys/keyctl_relabel.c
new file mode 100644
index 0000000..0276c7a
--- /dev/null
+++ b/tests/keys/keyctl_relabel.c
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <keyutils.h>
+#include <selinux/selinux.h>
+
+static void usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] newcon\n"
+		"Where:\n\t"
+		"-v      Print information.\n\t"
+		"newcon  New keyring context.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, result;
+	char *context, *keycreate_con;
+	char r_con[256];
+	bool verbose = false;
+	key_serial_t newring;
+
+	while ((opt = getopt(argc, argv, "v")) != -1) {
+		switch (opt) {
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			usage(argv[0]);
+		}
+	}
+
+	if (optind >= argc)
+		usage(argv[0]);
+
+	result = getcon(&context);
+	if (result < 0) {
+		fprintf(stderr, "Failed to obtain process context\n");
+		exit(1);
+	}
+	if (verbose)
+		printf("Process context: %s\n", context);
+	free(context);
+
+	result = setkeycreatecon(argv[optind]);
+	if (result < 0) {
+		fprintf(stderr, "Failed setkeycreatecon(): %s\n",
+			strerror(errno));
+		exit(2);
+	}
+
+	result = getkeycreatecon(&keycreate_con);
+	if (result < 0) {
+		fprintf(stderr, "Failed to obtain keycreate context\n");
+		exit(3);
+	}
+	if (verbose)
+		printf("New keycreate context: %s\n", keycreate_con);
+	free(keycreate_con);
+
+	newring = add_key("keyring", "my-keyring", NULL, 0,
+			  KEY_SPEC_THREAD_KEYRING);
+	if (newring < 0) {
+		fprintf(stderr, "Failed to add new keyring: %s\n",
+			strerror(errno));
+		exit(4);
+	}
+
+	result = keyctl(KEYCTL_GET_SECURITY, newring, r_con, sizeof(r_con));
+	if (result < 0) {
+		fprintf(stderr, "Failed to obtain key context: %s\n",
+			strerror(errno));
+		exit(5);
+	}
+
+	if (strcmp(argv[optind], r_con)) {
+		fprintf(stderr, "Relabel error - expected: %s got: %s\n",
+			argv[optind], r_con);
+		exit(6);
+	}
+
+	if (verbose) {
+		printf("'my-keyring' key ID: 0x%x\n", newring);
+		printf("'my-keyring' context:\n\t%s\n", r_con);
+	}
+
+	return 0;
+}
diff --git a/tests/keys/test b/tests/keys/test
new file mode 100755
index 0000000..4916e7c
--- /dev/null
+++ b/tests/keys/test
@@ -0,0 +1,98 @@
+#!/usr/bin/perl
+use Test::More;
+
+BEGIN {
+    $basedir = $0;
+    $basedir =~ s|(.*)/[^/]*|$1|;
+
+    $test_count = 13;
+
+    # allow info to be shown during tests
+    $v = $ARGV[0];
+    if ($v) {
+        if ( $v ne "-v" ) {
+            plan skip_all => "Invalid option (use -v)";
+        }
+    }
+    else {
+        $v = " ";
+    }
+
+    # From kernel 5.3 request_key() requires additional check of key { link }
+    $kvercur = `uname -r`;
+    chomp($kvercur);
+    $kverminstream = "5.3";
+    $test_link_53  = 0;
+
+    $result = `$basedir/../kvercmp $kvercur $kverminstream`;
+    if ( $result >= 0 ) {
+        $test_link_53 = 1;
+    }
+
+    plan tests => $test_count;
+}
+
+############ Test keyctl #############
+print "Test key class permissions\n";
+$result = system "runcon -t test_key_t $basedir/keyctl $v";
+ok( $result eq 0 );
+
+# Deny process { setkeycreate }
+$result = system "runcon -t test_no_setkeycreate_t $basedir/keyctl $v 2>&1";
+ok( $result >> 8 eq 3 );
+
+# Deny key { create }
+$result = system "runcon -t test_key_no_create_t $basedir/keyctl $v 2>&1";
+ok( $result >> 8 eq 3 );
+
+# Deny key { write }
+$result = system "runcon -t test_key_no_write_t $basedir/keyctl $v 2>&1";
+ok( $result >> 8 eq 5 );
+
+# Deny key { search }
+$result = system "runcon -t test_key_no_search_t $basedir/keyctl $v 2>&1";
+ok( $result >> 8 eq 8 );
+
+# Deny key { view }
+$result = system "runcon -t test_key_no_view_t $basedir/keyctl $v 2>&1";
+ok( $result >> 8 eq 10 );
+
+# Deny key { read }
+$result = system "runcon -t test_key_no_read_t $basedir/keyctl $v 2>&1";
+ok( $result >> 8 eq 11 );
+
+# Deny key { link }
+$result = system "runcon -t test_key_no_link_t $basedir/keyctl $v 2>&1";
+if ($test_link_53) {
+    ok( $result >> 8 eq 8 );
+}
+else {
+    ok( $result >> 8 eq 13 );
+}
+
+# Deny key { setattr }
+$result = system "runcon -t test_key_no_setattr_t $basedir/keyctl $v 2>&1";
+ok( $result >> 8 eq 14 );
+
+########### Change keyring context ##############
+print "Change keyring context\n";
+$result = system
+"runcon -t test_key_t $basedir/keyctl_relabel $v system_u:system_r:test_newcon_key_t:s0";
+ok( $result eq 0 );
+
+############ Test key_socket #############
+print "Test key_socket class\n";
+$result = system "runcon -t test_key_sock_t $basedir/key_sock $v";
+ok( $result eq 0 );
+
+# Deny capability { net_admin } - EPERM
+$result =
+  system "runcon -t test_key_sock_no_net_admin_t $basedir/key_sock $v 2>&1";
+ok( $result >> 8 eq 1 );
+
+# Deny key_socket { create } - EACCES
+$result =
+  system "runcon -t test_key_sock_no_create_t $basedir/key_sock $v 2>&1";
+ok( $result >> 8 eq 13 );
+
+exit;
