[PATCH 10/16] keyctl: Introduce a new operation KEYCTL_VERIFY_SIGNATURE

Vivek Goyal vgoyal at redhat.com
Tue Sep 10 17:44:25 EDT 2013


This is based on a patch david howells sent me. I have modified that
patch to meet my needs.

Extend kecytl() to add an option to verify signature of a user buffer.
One needs to pass in the signature type also so that respective handler
can be called. Currently I have defined a new signature type
KEYCTL_SIG_TYPE_IMA_DIGSIG, which sinifies signatures generated by IMA
subsystem.

Signed-off-by: Vivek Goyal <vgoyal at redhat.com>
---
 include/uapi/linux/keyctl.h | 16 +++++++++
 security/keys/compat.c      | 28 ++++++++++++++++
 security/keys/internal.h    |  2 ++
 security/keys/keyctl.c      | 79 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 125 insertions(+)

diff --git a/include/uapi/linux/keyctl.h b/include/uapi/linux/keyctl.h
index 840cb99..d7c7471 100644
--- a/include/uapi/linux/keyctl.h
+++ b/include/uapi/linux/keyctl.h
@@ -12,6 +12,17 @@
 #ifndef _LINUX_KEYCTL_H
 #define _LINUX_KEYCTL_H
 
+/* Data required to verify signature of a user buffer */
+struct keyctl_sig_data {
+	void *data;
+	size_t datalen;
+	void *sig;
+	size_t siglen;
+	unsigned long sig_type;
+	unsigned long keyring_id;
+	unsigned long flags;
+};
+
 /* special process keyring shortcut IDs */
 #define KEY_SPEC_THREAD_KEYRING		-1	/* - key ID for thread-specific keyring */
 #define KEY_SPEC_PROCESS_KEYRING	-2	/* - key ID for process-specific keyring */
@@ -57,5 +68,10 @@
 #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_VERIFY_SIGNATURE		23	/* use a key to verify a signature */
+
+/* Type of signatures */
+#define KEYCTL_SIG_TYPE_UNKNOWN			0
+#define KEYCTL_SIG_TYPE_INTEGRITY_DIGSIG	1 	/* Digital Signature generated by integrity subsystem utilities */
 
 #endif /*  _LINUX_KEYCTL_H */
diff --git a/security/keys/compat.c b/security/keys/compat.c
index bbd32c7..3af2cf2 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -15,6 +15,31 @@
 #include <linux/slab.h>
 #include "internal.h"
 
+struct compat_keyctl_sig_data {
+	compat_uptr_t data;
+	compat_size_t datalen;
+	compat_uptr_t sig;
+	compat_size_t siglen;
+	compat_ulong_t sig_type;
+	compat_ulong_t keyring_id;
+	compat_ulong_t flags;
+};
+
+static long compat_keyctl_verify_signature(const void __user *_sig_data)
+{
+	struct compat_keyctl_sig_data csig_data;
+	int result;
+
+	result = copy_from_user(&csig_data, _sig_data, sizeof(csig_data));
+	if (result)
+		return -EFAULT;
+
+	return __keyctl_verify_signature(csig_data.keyring_id,
+			compat_ptr(csig_data.data), csig_data.datalen,
+			compat_ptr(csig_data.sig), csig_data.siglen,
+			csig_data.sig_type, csig_data.flags);
+}
+
 /*
  * Instantiate a key with the specified compatibility multipart payload and
  * link the key into the destination keyring if one is given.
@@ -141,6 +166,9 @@ asmlinkage long compat_sys_keyctl(u32 option,
 	case KEYCTL_GET_PERSISTENT:
 		return keyctl_get_persistent(arg2, arg3);
 
+	case KEYCTL_VERIFY_SIGNATURE:
+		return compat_keyctl_verify_signature(compat_ptr(arg2));
+
 	default:
 		return -EOPNOTSUPP;
 	}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 80b2aac..f15acee 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -255,6 +255,8 @@ extern long keyctl_invalidate_key(key_serial_t);
 extern long keyctl_instantiate_key_common(key_serial_t,
 					  const struct iovec *,
 					  unsigned, size_t, key_serial_t);
+extern long keyctl_verify_signature(const void __user *_sig_data);
+extern long __keyctl_verify_signature(key_serial_t keyring_id, void __user *_data, size_t dlen, void __user *_sig, size_t siglen, unsigned long sig_type, unsigned long flags);
 #ifdef CONFIG_PERSISTENT_KEYRINGS
 extern long keyctl_get_persistent(uid_t, key_serial_t);
 extern unsigned persistent_keyring_expiry;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index cee72ce..84b7c3d 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -23,6 +23,8 @@
 #include <linux/vmalloc.h>
 #include <linux/security.h>
 #include <linux/uio.h>
+#include <linux/ima.h>
+#include <keys/system_keyring.h>
 #include <asm/uaccess.h>
 #include "internal.h"
 
@@ -1564,6 +1566,80 @@ error_keyring:
 	return ret;
 }
 
+long __keyctl_verify_signature(key_serial_t keyring_id, void __user *_data,
+				size_t dlen, void __user *_sig, size_t siglen,
+				unsigned long sig_type, unsigned long flags)
+{
+	void *sig;
+	long ret;
+	key_ref_t keyring_ref;
+
+	pr_devel("-->keyctl_verify_signature(,%zu,,%zu,%lu)\n",
+			dlen, siglen, sig_type);
+
+	if (!_data || !dlen || !_sig || !siglen || !keyring_id)
+		return -EINVAL;
+	/*
+	 * Possibly various signature handlers could scan signature and
+	 * claim it belongs to them and verify.
+	 */
+	if (sig_type == KEYCTL_SIG_TYPE_UNKNOWN)
+		return -EOPNOTSUPP;
+
+	/* Get the keyring which should be used */
+	keyring_ref = lookup_user_key(keyring_id, 0, KEY_SEARCH);
+	if (IS_ERR(keyring_ref))
+		return PTR_ERR(keyring_ref);
+
+
+	ret = -ENOMEM;
+	sig = kmalloc(siglen, GFP_KERNEL);
+	if (!sig)
+		goto error_keyref_put;
+
+	ret = -EFAULT;
+	if (copy_from_user(sig, _sig, siglen) != 0)
+		goto error_free_sig;
+
+	switch(sig_type) {
+	case KEYCTL_SIG_TYPE_INTEGRITY_DIGSIG:
+		ret = integrity_verify_user_buffer_digsig(
+					key_ref_to_ptr(keyring_ref),
+					_data, dlen, sig, siglen);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+error_free_sig:
+	kfree(sig);
+error_keyref_put:
+	key_ref_put(keyring_ref);
+	return ret;
+}
+
+/*
+ * Use a key to verify a signature.
+ *
+ * The key argument gives a key to use or a keyring in which a suitable key
+ * might be found.  The signature will be examined and an attempt will be made
+ * to determine the key to use from the information contained therein.
+ */
+long keyctl_verify_signature(const void __user *_sig_data)
+{
+	struct keyctl_sig_data sig_data;
+	int result;
+
+	result = copy_from_user(&sig_data, _sig_data, sizeof(sig_data));
+	if (result)
+		return -EFAULT;
+
+	return __keyctl_verify_signature(sig_data.keyring_id, sig_data.data,
+				sig_data.datalen, sig_data.sig, sig_data.siglen,
+				sig_data.sig_type, sig_data.flags);
+
+}
+
 /*
  * The key control system call
  */
@@ -1670,6 +1746,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3,
 	case KEYCTL_GET_PERSISTENT:
 		return keyctl_get_persistent((uid_t)arg2, (key_serial_t)arg3);
 
+	case KEYCTL_VERIFY_SIGNATURE:
+		return keyctl_verify_signature((const void __user *)arg2);
+
 	default:
 		return -EOPNOTSUPP;
 	}
-- 
1.8.3.1




More information about the kexec mailing list