linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 04/04] Add dsa key type
  2006-01-23 20:42   ` [PATCH 03/04] Add encryption ops to the keyctl syscall David Härdeman
@ 2006-01-23 20:42     ` David Härdeman
  2006-01-24 11:08       ` David Howells
  2006-01-24  4:33     ` [PATCH 03/04] Add encryption ops to the keyctl syscall Randy.Dunlap
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 17+ messages in thread
From: David Härdeman @ 2006-01-23 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: dhowells, david


Adds the dsa in-kernel key type.

Signed-off-by: David Härdeman <david@2gen.com>

--

Index: vanilla-kernel/security/Kconfig
===================================================================
--- vanilla-kernel.orig/security/Kconfig	2006-01-17 22:49:50.000000000 +0100
+++ vanilla-kernel/security/Kconfig	2006-01-23 18:45:29.000000000 +0100
@@ -21,6 +21,14 @@
 
 	  If you are unsure as to whether this is required, answer N.
 
+config KEYS_DSA_KEYS
+	tristate "Support DSA keys (EXPERIMENTAL)"
+	depends on KEYS && EXPERIMENTAL
+	select CRYPTO_MPILIB
+	select CRYPTO_DSA
+	help
+	  This option provides support for retaining DSA keys in the kernel.
+
 config KEYS_DEBUG_PROC_KEYS
 	bool "Enable the /proc/keys file by which all keys may be viewed"
 	depends on KEYS
Index: vanilla-kernel/security/keys/Makefile
===================================================================
--- vanilla-kernel.orig/security/keys/Makefile	2006-01-15 18:22:51.000000000 +0100
+++ vanilla-kernel/security/keys/Makefile	2006-01-23 18:46:00.000000000 +0100
@@ -13,4 +13,5 @@
 	user_defined.o
 
 obj-$(CONFIG_KEYS_COMPAT) += compat.o
+obj-$(CONFIG_KEYS_DSA_KEYS) += dsa_key.o
 obj-$(CONFIG_PROC_FS) += proc.o
Index: vanilla-kernel/security/keys/dsa_key.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ vanilla-kernel/security/keys/dsa_key.c	2006-01-23 18:46:00.000000000 +0100
@@ -0,0 +1,372 @@
+/* dsa_key.c: DSA key
+ *
+ * Copyright (C) 2005 David Härdeman (david@2gen.com). 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/err.h>
+#include <asm/uaccess.h>
+#include <linux/mpi.h>
+#include <linux/dsa.h>
+#include <linux/random.h>
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+#include <keys/user-type.h>
+#include "internal.h"
+
+static int dsa_instantiate(struct key *key, const void *data, size_t datalen);
+static int dsa_update(struct key *key, const void *data, size_t datalen);
+static void dsa_destroy(struct key *key);
+static long dsa_read(const struct key *key, 
+		     char __user *buffer, size_t buflen);
+static long dsa_encrypt(const struct key *key,
+			char __user *_data, size_t dlen,
+			char __user *_result, size_t rlen);
+
+static struct key_type key_type_dsa = {
+	.name		= "dsa",
+	.instantiate	= dsa_instantiate,
+	.update		= dsa_update,
+	.destroy	= dsa_destroy,
+	.read		= dsa_read,
+	.encrypt	= dsa_encrypt,
+	.match		= user_match,
+	.describe	= user_describe,
+};
+
+/****************
+ * Signs a chunk of data using key.
+ * Returns: signature.
+ */
+static char *
+sign(const struct key_payload_dsa *skey, 
+     const void *data, size_t datalen, unsigned int *rlen)
+{
+	struct crypto_tfm *tfm;
+	char *ret = NULL;
+	u8 *sig;
+	unsigned int sigsize;
+	int i;
+	struct scatterlist sg[1];
+
+	dprintk("dsa: entering sign\n");
+	tfm = crypto_alloc_tfm("dsa", 0);
+	if (!tfm)
+		goto out;
+
+	sigsize = crypto_tfm_alg_digestsize(tfm);
+	sig = kmalloc(sigsize, GFP_KERNEL);
+	if (!sig)
+		goto out_tfm;
+
+	crypto_digest_init(tfm);
+	i = crypto_digest_setkey(tfm, (const u8 *)skey, sizeof(skey));
+	if (i) {
+		printk("dsa: crypto_digest_setkey failed with error %i\n", i);
+		goto out_sig;
+	}
+
+	sg_init_one(sg, (u8 *)data, datalen);
+	crypto_digest_update(tfm, sg, 1);
+	crypto_digest_final(tfm, sig);
+	ret = sig;
+	*rlen = sigsize;
+	goto out_tfm;
+
+out_sig:
+	kfree(sig);
+out_tfm:
+	crypto_free_tfm(tfm);
+out:
+	return ret;
+}
+
+/****************
+ * Test whether the secret key is valid.
+ * Returns: if this is a valid key.
+ */
+static int check_secret_key(struct key_payload_dsa *skey)
+{
+	int rc;
+	MPI y;
+
+	/* y = g^x mod p */
+	dprintk("dsa: In check secret\n");
+	y = mpi_alloc(mpi_get_nlimbs(skey->part[DSA_PART_Y]));
+	rc = mpi_powm(y, skey->part[DSA_PART_G], skey->part[DSA_PART_X], skey->part[DSA_PART_P]);
+	rc = !mpi_cmp(y, skey->part[DSA_PART_Y]);
+
+	mpi_free(y);
+	return rc;
+}
+
+/*****************************************************************************/
+/*
+ * create a dsa key payload
+ */
+static int dsa_create_payload(struct key_payload_dsa **payload, struct key *key, 
+			      const void *data, size_t datalen)
+{
+	int ret, i;
+	unsigned int remain, read;
+	const unsigned char *ptr;
+
+	dprintk("dsa: entering dsa_create_payload\n");
+
+	ret = -EINVAL;
+	if (datalen <= 0 || datalen > 32767 || !data)
+		goto out1;
+
+	ret = -ENOMEM;
+	*payload = kmalloc(sizeof(struct key_payload_dsa), GFP_KERNEL);
+	if (!(*payload))
+		goto out1;
+
+	ret = key_payload_reserve(key, datalen);
+	if (ret < 0)
+		goto out2;
+
+	/* read each mpi number from buffer */
+	remain = read = (unsigned int)datalen;
+	ptr = data;
+	ret = 0;
+	for (i = 0; i < DSA_PARTS; i++) {
+		dprintk("dsa: in loop %i, remain is %u\n", i, remain);
+		(*payload)->part[i] = mpi_read_from_buffer(ptr, &read);
+		if (!((*payload)->part[i]))
+			ret = -EINVAL;
+		ptr += read;
+		remain -= read;
+		read = remain;
+		dprintk("dsa: end loop\n");
+	}
+
+	if (ret < 0)
+		goto out3;
+
+	/* check validity */
+	ret = -EINVAL;
+	if(check_secret_key(*payload)) {
+		ret = 0;
+		dprintk("dsa: valid\n");
+		goto out1;
+	}
+
+out3:
+	printk("dsa: attempt to add invalid key\n");
+	for (i = 0; i < DSA_PARTS; i++)
+		mpi_free((*payload)->part[i]);
+out2:
+	kfree(*payload);
+out1:
+	return ret;
+
+} /* end dsa_instantiate() */
+
+/*****************************************************************************/
+/*
+ * instantiate a dsa key
+ */
+static int dsa_instantiate(struct key *key, const void *data, size_t datalen)
+{
+	struct key_payload_dsa *dsa_key;
+	int ret;
+
+	dprintk("dsa: entering dsa_instantiate\n");
+	ret = dsa_create_payload(&dsa_key, key, data, datalen);
+	if (ret == 0)
+		key->payload.data = dsa_key;
+
+	return ret;
+
+} /* end dsa_instantiate() */
+
+/*****************************************************************************/
+/*
+ * update a user defined key
+ */
+static int dsa_update(struct key *key, const void *data, size_t datalen)
+{
+	struct key_payload_dsa *new_payload;
+	int ret;
+
+	dprintk("dsa: entering dsa_update\n");
+	ret = dsa_create_payload(&new_payload, key, data, datalen);
+	if (ret == 0) {
+		dprintk("dsa: dsa_create_payload success\n");
+		/* this destroys the old payload, not the entire key */
+		dsa_destroy(key);
+		key->payload.data = new_payload;
+		key->expiry = 0;
+	}
+	
+	return ret;
+
+} /* end dsa_update() */
+
+/*****************************************************************************/
+/*
+ * dispose of the key payload
+ */
+static void dsa_destroy(struct key *key)
+{
+	struct key_payload_dsa *dsa_key;
+	int i;
+
+	dprintk("dsa: entering dsa_destroy\n");
+	dsa_key = key->payload.data;
+	if (dsa_key) {
+		for (i = 0; i < DSA_PARTS; i++)
+			mpi_free(dsa_key->part[i]);
+		kfree(dsa_key);
+	}
+
+} /* end dsa_destroy() */
+
+/*****************************************************************************/
+/*
+ * read the key data
+ */
+static long dsa_read(const struct key *key, char __user *buffer, size_t buflen)
+{
+	unsigned char *xbuffer[DSA_PUBLIC_PARTS];
+	unsigned nbytes[DSA_PUBLIC_PARTS];
+	unsigned nbits[DSA_PUBLIC_PARTS];
+	struct key_payload_dsa *dsa_key;
+	int i;
+	char *result, *tmp;
+	size_t reslen;
+	long ret;
+
+	dprintk("dsa: entering dsa_read\n");
+	ret = -EINVAL;
+	dsa_key = (struct key_payload_dsa *)key->payload.data;
+	if (!dsa_key)
+		goto out1;
+
+	/* 4 x 2 bytes to store mpi sizes */
+	reslen = 8;
+	memset(xbuffer, 0, sizeof(xbuffer));
+	ret = -ENOMEM;
+
+	for (i = 0; i < DSA_PUBLIC_PARTS; i++) {
+		xbuffer[i] = mpi_get_buffer(dsa_key->part[i], &nbytes[i], NULL);
+		if (!xbuffer[i]) {
+			dprintk("dsa: failed to get buffer\n");
+			goto out2;
+		}
+		reslen += nbytes[i];
+		nbits[i] = mpi_get_nbits(dsa_key->part[i]);
+	}
+
+	result = kmalloc(reslen, GFP_KERNEL);
+	if (!result)
+		goto out2;
+
+	tmp = result;
+	for (i = 0; i < DSA_PUBLIC_PARTS; i++) {
+		dprintk("dsa: checking part %i\n", i);
+		dprintk("dsa: nbytes is %i, nbits is %i, topbyte is %2hx, botbyte is %2hx\n",
+			nbytes[i], nbits[i], ((nbits[i] >> 8) & 0xff), ((nbits[i]) & 0xff));
+		MPI_WSIZE(tmp, nbits[i]);
+		memcpy(tmp, xbuffer[i], nbytes[i]);
+		tmp += nbytes[i];
+	}
+
+	ret = -EFAULT;
+	if (copy_to_user(buffer, result, min(reslen, buflen)) == 0)
+		ret = reslen;
+
+	memset(result, 0, reslen);
+	kfree(result);
+	
+out2:
+	for (i = 0; i < DSA_PUBLIC_PARTS; i++) {
+		memset(xbuffer[i], 0, nbytes[i]);
+		kfree(xbuffer[i]);
+	}
+out1:
+	dprintk("dsa: leving dsa_read\n");
+	return ret;
+
+} /* end dsa_read() */
+
+/*****************************************************************************/
+/*
+ * encrypt data using a key
+ */
+static long dsa_encrypt(const struct key *key,
+		     char __user *data, size_t dlen,
+		     char __user *result, size_t rlen)
+{
+	char *signature;
+	char *inbuf;
+	long ret;
+	size_t siglen = 0;
+
+	dprintk("dsa: entering dsa_encrypt\n");
+	ret = -ENOMEM;
+	inbuf = kmalloc(dlen, GFP_KERNEL);
+	if (!inbuf)
+		goto out1;
+
+	ret = -EFAULT;
+	/* pull the data to sign into kernel space */
+	if (copy_from_user(inbuf, data, dlen))
+		goto out2;
+
+	/* sign it */
+	signature = sign((struct key_payload_dsa *)key->payload.data,
+			 inbuf, dlen, &siglen);
+	if (!signature)
+		goto out2;
+
+	/* push the result to userspace */
+	if(copy_to_user(result, signature, min(rlen, siglen)) == 0)
+		ret = siglen;
+
+	memset(signature, 0, siglen);
+	kfree(signature);
+out2:
+	memset(inbuf, 0, dlen);
+	kfree(inbuf);
+out1:
+	return ret;
+} /* end dsa_encrypt() */
+
+static int __init dsa_init(void)
+{
+	int ret;
+
+	ret = register_key_type(&key_type_dsa);
+	if (ret < 0)
+		printk("dsa_key: failed to register key type\n");
+	else
+		printk("dsa_key: new key type registered\n");
+
+	return ret;
+}
+
+static void __exit dsa_exit (void)
+{
+	printk("dsa_key: unregistering key type\n");
+	unregister_key_type(&key_type_dsa);
+}
+
+module_init(dsa_init);
+module_exit(dsa_exit);
+
+MODULE_AUTHOR("David Härdeman");
+MODULE_DESCRIPTION("DSA key support");
+MODULE_LICENSE("GPL");


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

* [PATCH 03/04] Add encryption ops to the keyctl syscall
  2006-01-23 20:42 ` [PATCH 02/04] Add dsa crypto ops David Härdeman
@ 2006-01-23 20:42   ` David Härdeman
  2006-01-23 20:42     ` [PATCH 04/04] Add dsa key type David Härdeman
                       ` (3 more replies)
  2006-01-24  1:22   ` [PATCH 02/04] Add dsa crypto ops Herbert Xu
  1 sibling, 4 replies; 17+ messages in thread
From: David Härdeman @ 2006-01-23 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: dhowells, david


Changes the keyctl syscall to accept six arguments (is it valid to do so?)
and adds encryption as one of the supported ops for in-kernel keys.

Signed-off-by: David Härdeman <david@2gen.com>

--

Index: vanilla-kernel/include/linux/compat.h
===================================================================
--- vanilla-kernel.orig/include/linux/compat.h	2006-01-15 18:22:51.000000000 +0100
+++ vanilla-kernel/include/linux/compat.h	2006-01-23 18:40:52.000000000 +0100
@@ -132,8 +132,8 @@
 long compat_sys_shmctl(int first, int second, void __user *uptr);
 long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
 		unsigned nsems, const struct compat_timespec __user *timeout);
-asmlinkage long compat_sys_keyctl(u32 option,
-			      u32 arg2, u32 arg3, u32 arg4, u32 arg5);
+asmlinkage long compat_sys_keyctl(u32 option, u32 arg2, u32 arg3, 
+                                  u32 arg4, u32 arg5, u32 arg6);
 
 asmlinkage ssize_t compat_sys_readv(unsigned long fd,
 		const struct compat_iovec __user *vec, unsigned long vlen);
Index: vanilla-kernel/include/linux/key.h
===================================================================
--- vanilla-kernel.orig/include/linux/key.h	2006-01-17 22:49:50.000000000 +0100
+++ vanilla-kernel/include/linux/key.h	2006-01-23 18:40:52.000000000 +0100
@@ -220,6 +220,17 @@
 	 */
 	long (*read)(const struct key *key, char __user *buffer, size_t buflen);
 
+	/* encrypt data using a key (optional)
+	 * - permission checks will be done by the caller
+	 * - the key's semaphore will be readlocked by the caller
+	 * - should return the amount of data that would be returned from the
+         *   encryption even if the buffer is NULL
+         * - expects the output buffer to be able to hold the result
+	 */
+	long (*encrypt)(const struct key *key,
+                        char __user *inbuffer, size_t inbuflen,
+                        char __user *outbuffer, size_t outbuflen);
+
 	/* handle request_key() for this type instead of invoking
 	 * /sbin/request-key (optional)
 	 * - key is the key to instantiate
Index: vanilla-kernel/include/linux/keyctl.h
===================================================================
--- vanilla-kernel.orig/include/linux/keyctl.h	2006-01-17 22:49:50.000000000 +0100
+++ vanilla-kernel/include/linux/keyctl.h	2006-01-23 18:40:52.000000000 +0100
@@ -49,5 +49,6 @@
 #define KEYCTL_SET_REQKEY_KEYRING	14	/* set default request-key keyring */
 #define KEYCTL_SET_TIMEOUT		15	/* set key timeout */
 #define KEYCTL_ASSUME_AUTHORITY		16	/* assume request_key() authorisation */
+#define KEYCTL_ENCRYPT                  17      /* encrypt a chunk of data using key */
 
 #endif /*  _LINUX_KEYCTL_H */
Index: vanilla-kernel/include/linux/syscalls.h
===================================================================
--- vanilla-kernel.orig/include/linux/syscalls.h	2006-01-17 22:49:50.000000000 +0100
+++ vanilla-kernel/include/linux/syscalls.h	2006-01-23 18:40:52.000000000 +0100
@@ -504,8 +504,9 @@
 				const char __user *_callout_info,
 				key_serial_t destringid);
 
-asmlinkage long sys_keyctl(int cmd, unsigned long arg2, unsigned long arg3,
-			   unsigned long arg4, unsigned long arg5);
+asmlinkage long sys_keyctl(int cmd, unsigned long arg2, 
+                           unsigned long arg3, unsigned long arg4, 
+                           unsigned long arg5, unsigned long arg6);
 
 asmlinkage long sys_ioprio_set(int which, int who, int ioprio);
 asmlinkage long sys_ioprio_get(int which, int who);
Index: vanilla-kernel/security/keys/compat.c
===================================================================
--- vanilla-kernel.orig/security/keys/compat.c	2006-01-17 22:49:50.000000000 +0100
+++ vanilla-kernel/security/keys/compat.c	2006-01-23 18:44:01.000000000 +0100
@@ -23,8 +23,8 @@
  *   registers on taking a 32-bit syscall are zero
  * - if you can, you should call sys_keyctl directly
  */
-asmlinkage long compat_sys_keyctl(u32 option,
-				  u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+asmlinkage long compat_sys_keyctl(u32 option, u32 arg2, u32 arg3, 
+				  u32 arg4, u32 arg5, u32 arg6)
 {
 	switch (option) {
 	case KEYCTL_GET_KEYRING_ID:
@@ -80,6 +80,11 @@
 	case KEYCTL_ASSUME_AUTHORITY:
 		return keyctl_assume_authority(arg2);
 
+	case KEYCTL_ENCRYPT:
+		return keyctl_encrypt_with_key(arg2,
+					       compat_ptr(arg3), arg4,
+					       compat_ptr(arg5), arg6);
+
 	default:
 		return -EOPNOTSUPP;
 	}
Index: vanilla-kernel/security/keys/keyctl.c
===================================================================
--- vanilla-kernel.orig/security/keys/keyctl.c	2006-01-17 22:49:50.000000000 +0100
+++ vanilla-kernel/security/keys/keyctl.c	2006-01-23 18:44:02.000000000 +0100
@@ -1066,10 +1066,71 @@
 
 /*****************************************************************************/
 /*
+ * encrypt a chunk of data using a specified key
+ * - implements keyctl(KEYCTL_ENCRYPT)
+ */
+long keyctl_encrypt_with_key(key_serial_t keyid,
+			     const void __user *data,
+			     size_t dlen,
+			     const void __user *result,
+			     size_t rlen)
+{
+	struct key *key;
+	key_ref_t key_ref;
+	long ret;
+
+	/* find the key first */
+	key_ref = lookup_user_key(NULL, keyid, 0, 0, 0);
+	if (IS_ERR(key_ref)) {
+		ret = -ENOKEY;
+		goto error;
+	}
+
+	key = key_ref_to_ptr(key_ref);
+
+	/* see if we can read it directly */
+	ret = key_permission(key_ref, KEY_READ);
+	if (ret == 0)
+		goto can_read_key;
+	if (ret != -EACCES)
+		goto error;
+
+	/* we can't; see if it's searchable from this process's keyrings
+	 * - we automatically take account of the fact that it may be
+	 *   dangling off an instantiation key
+	 */
+	if (!is_key_possessed(key_ref)) {
+		ret = -EACCES;
+		goto error2;
+	}
+
+	/* the key is probably readable - now try to read it */
+ can_read_key:
+	ret = key_validate(key);
+	if (ret == 0) {
+		ret = -EOPNOTSUPP;
+		if (key->type->encrypt) {
+			/* encrypt the data with the semaphore held (since we
+			 * might sleep) */
+			down_read(&key->sem);
+			ret = key->type->encrypt(key, data, dlen, result, rlen);
+			up_read(&key->sem);
+		}
+	}
+
+ error2:
+	key_put(key);
+ error:
+	return ret;
+} /* end keyctl_encrypt_with_key() */
+
+/*****************************************************************************/
+/*
  * the key control system call
  */
-asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
-			   unsigned long arg4, unsigned long arg5)
+asmlinkage long sys_keyctl(int option, unsigned long arg2, 
+			   unsigned long arg3, unsigned long arg4, 
+			   unsigned long arg5, unsigned long arg6)
 {
 	switch (option) {
 	case KEYCTL_GET_KEYRING_ID:
@@ -1144,6 +1205,13 @@
 	case KEYCTL_ASSUME_AUTHORITY:
 		return keyctl_assume_authority((key_serial_t) arg2);
 
+	case KEYCTL_ENCRYPT:
+		return keyctl_encrypt_with_key((key_serial_t) arg2,
+					       (const char __user *) arg3,
+					       (size_t) arg4,
+					       (const char __user *) arg5,
+					       (size_t) arg6);
+
 	default:
 		return -EOPNOTSUPP;
 	}


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

* [PATCH 02/04] Add dsa crypto ops
       [not found] <11380489522552@2gen.com>
@ 2006-01-23 20:42 ` David Härdeman
  2006-01-23 20:42   ` [PATCH 03/04] Add encryption ops to the keyctl syscall David Härdeman
  2006-01-24  1:22   ` [PATCH 02/04] Add dsa crypto ops Herbert Xu
  2006-01-24 10:37 ` [PATCH 01/04] Add multi-precision-integer maths library David Howells
  1 sibling, 2 replies; 17+ messages in thread
From: David Härdeman @ 2006-01-23 20:42 UTC (permalink / raw)
  To: linux-kernel; +Cc: dhowells, david


Adds dsa cryptographic operations. Since a dsa signature is always two
160-bit integer, I've modeled the dsa crypto as a hash algorithm.

Signed-off-by: David Härdeman <david@2gen.com>

--

Index: vanilla-kernel/crypto/Kconfig
===================================================================
--- vanilla-kernel.orig/crypto/Kconfig	2006-01-22 22:02:20.000000000 +0100
+++ vanilla-kernel/crypto/Kconfig	2006-01-22 22:08:27.000000000 +0100
@@ -342,6 +342,13 @@
 	  Multiprecision maths library from GnuPG. Used for some
 	  crypto algorithms.
 
+config CRYPTO_DSA
+	tristate "Digital Signature Algorithm (EXPERIMENTAL)"
+	depends on CRYPTO && CRYPTO_MPILIB && EXPERIMENTAL
+	help
+	  Digital Signature Algorithm is used in a number of applications
+	  such as ssh and gpg.
+
 config CRYPTO_TEST
 	tristate "Testing module"
 	depends on CRYPTO
Index: vanilla-kernel/crypto/Makefile
===================================================================
--- vanilla-kernel.orig/crypto/Makefile	2006-01-22 22:02:37.000000000 +0100
+++ vanilla-kernel/crypto/Makefile	2006-01-22 22:08:27.000000000 +0100
@@ -30,6 +30,7 @@
 obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o
 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
+obj-$(CONFIG_CRYPTO_DSA) += dsa.o
 obj-$(CONFIG_CRYPTO_MPILIB) += mpi/
 
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
Index: vanilla-kernel/crypto/dsa.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ vanilla-kernel/crypto/dsa.c	2006-01-22 22:08:11.000000000 +0100
@@ -0,0 +1,230 @@
+/*
+ * DSA Digital Signature Algorithm (FIPS-186).
+ *
+ * Copyright (c) 2005 David Härdeman <david@2gen.com>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/crypto.h>
+#include <linux/mpi.h>
+#include <linux/dsa.h>
+#include <linux/random.h>
+#include "../security/keys/internal.h"
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+
+
+/****************
+ * Generate a random secret exponent k less than q
+ */
+static MPI
+gen_k(MPI q)
+{
+	MPI k = mpi_alloc(mpi_get_nlimbs(q));
+	unsigned int nbits = mpi_get_nbits(q);
+	unsigned int nbytes = (nbits + 7)/8;
+	char *rndbuf = NULL;
+
+	dprintk("dsa: choosing a random k\n");
+
+	while(1) {
+		if (!rndbuf) {
+			rndbuf = kmalloc(nbytes, GFP_KERNEL);
+			if (!rndbuf) {
+				printk("dsa: failed to create buffer\n");
+				return NULL;
+			}
+			get_random_bytes(rndbuf, nbytes);
+		} else {
+			/* change only some of the higher bits */
+			get_random_bytes(rndbuf, min(nbytes, (unsigned int)4));
+		}
+
+		mpi_set_buffer(k, rndbuf, nbytes, 0);
+		if(mpi_test_bit( k, nbits - 1)) {
+			mpi_set_highbit(k, nbits - 1);
+		} else {
+			mpi_set_highbit(k, nbits - 1);
+			mpi_clear_bit(k, nbits - 1);
+		}
+
+		/* check: k < q */
+		if(!(mpi_cmp(k, q) < 0))
+			continue;
+
+		/* check: k > 0 */
+		if(!(mpi_cmp_ui(k, 0) > 0))
+			continue;
+
+		/* okay */
+		break;
+	}
+
+	kfree(rndbuf);
+	return k;
+}
+
+static void
+sign_hash(MPI r, MPI s, MPI hash, struct key_payload_dsa *skey)
+{
+	MPI k, kinv, tmp;
+
+	/* select a random k with 0 < k < q */
+	k = gen_k(skey->part[DSA_PART_Q]);
+	if (!k) {
+		printk("dsa: failed to create buffer\n");
+		return;
+	}
+
+	/* r = (g^k mod p) mod q */
+	mpi_powm(r, skey->part[DSA_PART_G], k, skey->part[DSA_PART_P]);
+	mpi_fdiv_r(r, r, skey->part[DSA_PART_Q]);
+
+	/* kinv = k^(-1) mod q */
+	kinv = mpi_alloc(mpi_get_nlimbs(k));
+	mpi_invm(kinv, k, skey->part[DSA_PART_Q]);
+
+	/* s = (kinv * ( hash + x * r)) mod q */
+	tmp = mpi_alloc(mpi_get_nlimbs(skey->part[DSA_PART_P]));
+	mpi_mul(tmp, skey->part[DSA_PART_X], r);
+	mpi_add(tmp, tmp, hash);
+	mpi_mulm(s , kinv, tmp, skey->part[DSA_PART_Q]);
+
+	mpi_free(k);
+	mpi_free(kinv);
+	mpi_free(tmp);
+}
+
+struct dsa_ctx {
+	struct crypto_tfm *sha1;
+	struct key_payload_dsa *key;
+};
+
+static int dsa_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+{
+	struct dsa_ctx *dctx = ctx;
+
+	if (keylen != sizeof(struct key_payload_dsa *)) {
+		printk("Invalid key size in dsa_setkey\n");
+		return -EINVAL;
+	}
+
+	dctx->key = (struct key_payload_dsa *)key;
+	return 0;
+}
+
+static void dsa_init(void *ctx)
+{
+	struct dsa_ctx *dctx = ctx;
+
+	dctx->key = NULL;
+	dctx->sha1 = crypto_alloc_tfm("sha1", 0);
+	if (!dctx->sha1)
+		printk("dsa_init: failed to allocate sha1 tfm\n");
+	else
+		crypto_digest_init(dctx->sha1);
+}
+
+static void dsa_update(void *ctx, const u8 *data, unsigned int dlen)
+{
+	struct scatterlist sg[1];
+	struct dsa_ctx *dctx = ctx;
+
+	if (!dctx->sha1)
+		return;
+
+	sg_init_one(sg, (u8 *)data, dlen);
+	crypto_digest_update(dctx->sha1, sg, 1);
+}
+
+static void dsa_final(void *ctx, u8 *out)
+{
+	struct dsa_ctx *dctx = ctx;
+	unsigned int dsize = crypto_tfm_alg_digestsize(dctx->sha1);
+	u8 buffer[dsize];
+	MPI hash, r, s;
+	u8 *outp = out;
+	unsigned int rbytes, rbits, sbytes, sbits;
+	char *rbuf, *sbuf;
+
+	if (!dctx->sha1)
+		return;
+
+	crypto_digest_final(dctx->sha1, buffer);
+	crypto_free_tfm(dctx->sha1);
+	dctx->sha1 = NULL;
+
+	hash = mpi_alloc(1);
+	r = mpi_alloc(1);
+	s = mpi_alloc(1);
+	if (!hash || !r || !s) {
+		printk("dsa_final: failed to allocate mpis\n");
+		goto out1;
+	}
+
+	mpi_set_buffer(hash, buffer, dsize, 0);
+	sign_hash(r, s, hash, dctx->key);
+	rbuf = mpi_get_buffer(r, &rbytes, NULL);
+	sbuf = mpi_get_buffer(s, &sbytes, NULL);
+	if (!rbuf || !sbuf) {
+		printk("dsa_final: failed to allocate buffers\n");
+		goto out2;
+	}
+
+	rbits = mpi_get_nbits(r);
+	MPI_WSIZE(outp, rbits);
+	memcpy(outp, rbuf, rbytes);
+	outp += rbytes;
+
+	sbits = mpi_get_nbits(s);
+	MPI_WSIZE(outp, sbits);
+	memcpy(outp, sbuf, sbytes);
+
+out2:
+	kfree(rbuf);
+	kfree(sbuf);
+out1:
+	mpi_free(hash);
+	mpi_free(r);
+	mpi_free(s);
+}
+
+static struct crypto_alg alg = {
+	.cra_name	=	"dsa",
+	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize	=	DSA_HMAC_BLOCK_SIZE,
+	.cra_ctxsize	=	sizeof(struct dsa_ctx),
+	.cra_module	=	THIS_MODULE,
+	.cra_list	=	LIST_HEAD_INIT(alg.cra_list),
+	.cra_u		=	{ .digest = {
+	.dia_digestsize	=	DSA_DIGEST_SIZE,
+	.dia_init   	= 	dsa_init,
+	.dia_update 	=	dsa_update,
+	.dia_final  	=	dsa_final,
+	.dia_setkey  	=	dsa_setkey } }
+};
+
+static int __init init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("David Härdeman");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DSA Digital Signature Algorithm");
Index: vanilla-kernel/include/linux/dsa.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ vanilla-kernel/include/linux/dsa.h	2006-01-22 22:07:58.000000000 +0100
@@ -0,0 +1,39 @@
+/* dsa.h: digital signature architecture
+ *
+ * Copyright (C) 2005 David Härdeman (david@2gen.com).
+ * 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.
+ */
+
+#ifndef _LINUX_DSA_H
+#define _LINUX_DSA_H
+#ifdef __KERNEL__
+
+#include <linux/mpi.h>
+
+#define DSA_DIGEST_SIZE         44
+#define DSA_HMAC_BLOCK_SIZE     64
+#define DSA_PART_P              0
+#define DSA_PART_Q              1
+#define DSA_PART_G              2
+#define DSA_PART_Y              3
+#define DSA_PART_X              4
+#define DSA_PARTS               5
+#define DSA_PUBLIC_PARTS        4
+
+struct key_payload_dsa {
+    MPI part[DSA_PARTS]; /* p,q,g,y,x */
+};
+
+#if 0
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...) do { } while(0)
+#endif
+
+#endif
+#endif


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

* Re: [PATCH 02/04] Add dsa crypto ops
  2006-01-23 20:42 ` [PATCH 02/04] Add dsa crypto ops David Härdeman
  2006-01-23 20:42   ` [PATCH 03/04] Add encryption ops to the keyctl syscall David Härdeman
@ 2006-01-24  1:22   ` Herbert Xu
  2006-01-24  6:49     ` David Härdeman
  1 sibling, 1 reply; 17+ messages in thread
From: Herbert Xu @ 2006-01-24  1:22 UTC (permalink / raw)
  To: David H?rdeman; +Cc: linux-kernel, dhowells, david

David H?rdeman <david@2gen.com> wrote:
>
> +static int dsa_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
> +{
> +       struct dsa_ctx *dctx = ctx;
> +
> +       if (keylen != sizeof(struct key_payload_dsa *)) {
> +               printk("Invalid key size in dsa_setkey\n");
> +               return -EINVAL;
> +       }
> +
> +       dctx->key = (struct key_payload_dsa *)key;
> +       return 0;
> +}

This is bad.  You're putting a pointer to an object with an unknown
lifetime into the tfm.

Is there anything wrong with allocating the memory for it and storing
the key in the tfm like everyone else?

Cheers,
-- 
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

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

* Re: [PATCH 03/04] Add encryption ops to the keyctl syscall
  2006-01-23 20:42   ` [PATCH 03/04] Add encryption ops to the keyctl syscall David Härdeman
  2006-01-23 20:42     ` [PATCH 04/04] Add dsa key type David Härdeman
@ 2006-01-24  4:33     ` Randy.Dunlap
  2006-01-24 10:58     ` David Howells
  2006-01-24 11:09     ` David Howells
  3 siblings, 0 replies; 17+ messages in thread
From: Randy.Dunlap @ 2006-01-24  4:33 UTC (permalink / raw)
  To: David Härdeman; +Cc: linux-kernel, dhowells

On Mon, 23 Jan 2006 21:42:32 +0100 David Härdeman wrote:

> 
> Changes the keyctl syscall to accept six arguments (is it valid to do so?)
> and adds encryption as one of the supported ops for in-kernel keys.

Does this say anything about the amount of syscall testing
that this code has had?

---
~Randy

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

* Re: [PATCH 02/04] Add dsa crypto ops
  2006-01-24  1:22   ` [PATCH 02/04] Add dsa crypto ops Herbert Xu
@ 2006-01-24  6:49     ` David Härdeman
  0 siblings, 0 replies; 17+ messages in thread
From: David Härdeman @ 2006-01-24  6:49 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-kernel, dhowells

On Tue, Jan 24, 2006 at 12:22:02PM +1100, Herbert Xu wrote:
>David H?rdeman <david@2gen.com> wrote:
>>
>> +static int dsa_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
>> +{
>> +       struct dsa_ctx *dctx = ctx;
>> +
>> +       if (keylen != sizeof(struct key_payload_dsa *)) {
>> +               printk("Invalid key size in dsa_setkey\n");
>> +               return -EINVAL;
>> +       }
>> +
>> +       dctx->key = (struct key_payload_dsa *)key;
>> +       return 0;
>> +}
>
>This is bad.  You're putting a pointer to an object with an unknown
>lifetime into the tfm.
>
>Is there anything wrong with allocating the memory for it and storing
>the key in the tfm like everyone else?

No, not at all, it's a mistake and I'll change it...


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

* Re: [PATCH 01/04] Add multi-precision-integer maths library
       [not found] <11380489522552@2gen.com>
  2006-01-23 20:42 ` [PATCH 02/04] Add dsa crypto ops David Härdeman
@ 2006-01-24 10:37 ` David Howells
  2006-01-25 20:46   ` David Härdeman
  2006-01-26  9:45   ` David Howells
  1 sibling, 2 replies; 17+ messages in thread
From: David Howells @ 2006-01-24 10:37 UTC (permalink / raw)
  To: David =?iso-8859-1?Q?H=E4rdeman?=; +Cc: linux-kernel, dhowells

David Härdeman <david@2gen.com> wrote:

> Adds the multi-precision-integer maths library which was originally taken
> from GnuPG and ported to the kernel by David Howells in 2004
> (http://people.redhat.com/~dhowells/modsign/modsign-269rc4mm1-2.diff.bz2)

You should update these files from a latest Fedora, Rawhide or RHEL kernel to
pick up the bug fixes that have been made.

David

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

* Re: [PATCH 03/04] Add encryption ops to the keyctl syscall
  2006-01-23 20:42   ` [PATCH 03/04] Add encryption ops to the keyctl syscall David Härdeman
  2006-01-23 20:42     ` [PATCH 04/04] Add dsa key type David Härdeman
  2006-01-24  4:33     ` [PATCH 03/04] Add encryption ops to the keyctl syscall Randy.Dunlap
@ 2006-01-24 10:58     ` David Howells
  2006-01-25 20:40       ` David Härdeman
  2006-01-26  9:43       ` David Howells
  2006-01-24 11:09     ` David Howells
  3 siblings, 2 replies; 17+ messages in thread
From: David Howells @ 2006-01-24 10:58 UTC (permalink / raw)
  To: David =?iso-8859-1?Q?H=E4rdeman?=; +Cc: linux-kernel, dhowells


David Härdeman <david@2gen.com> wrote:

> Changes the keyctl syscall to accept six arguments (is it valid to do so?)
> and adds encryption as one of the supported ops for in-kernel keys.

I tried to avoid doing that for it required arch support as I recall, but I'm
not sure which arch I was thinking of. It looks like it ought to be okay...
it's no worse than mmap.

> +	 * - should return the amount of data that would be returned from the
> +         *   encryption even if the buffer is NULL
> +         * - expects the output buffer to be able to hold the result
> +	 */

Can you use TAB chars here please.

>  #define KEYCTL_ASSUME_AUTHORITY		16	/* assume request_key() authorisation */
> +#define KEYCTL_ENCRYPT                  17      /* encrypt a chunk of data using key */

And here.

> +	key = key_ref_to_ptr(key_ref);
> +
> +	/* see if we can read it directly */
> +	ret = key_permission(key_ref, KEY_READ);

You don't actually need to calculate key until after you've done all those
checks, so I'd move it further down the file. You can use the function to
release key references in the error handling or have a separate error handling
return path.

> +			down_read(&key->sem);
> +			ret = key->type->encrypt(key, data, dlen, result, rlen);
> +			up_read(&key->sem);

Do we really want to restrict the key type implementor to using the r/w
semaphore. Would it be better to let the type decide whether it wants to use
the semaphore or let it use RCU if it so desires?

David

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

* Re: [PATCH 04/04] Add dsa key type
  2006-01-23 20:42     ` [PATCH 04/04] Add dsa key type David Härdeman
@ 2006-01-24 11:08       ` David Howells
  2006-01-25 19:14         ` David Härdeman
  2006-01-26  9:41         ` David Howells
  0 siblings, 2 replies; 17+ messages in thread
From: David Howells @ 2006-01-24 11:08 UTC (permalink / raw)
  To: David =?iso-8859-1?Q?H=E4rdeman?=; +Cc: linux-kernel, dhowells

David Härdeman <david@2gen.com> wrote:

> Adds the dsa in-kernel key type.

Please add a header file in include/keys/ to provide access to the key type
definition and any special payload structures you use.

> +static char *
> +sign(const struct key_payload_dsa *skey, 

Please be consistent about sticking prefixes on the names of your
functions. This ought to be called something like dsa_sign.

> +		printk("dsa: crypto_digest_setkey failed with error %i\n", i);

Should involve KERN_ERR or something like.

David

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

* Re: [PATCH 03/04] Add encryption ops to the keyctl syscall
  2006-01-23 20:42   ` [PATCH 03/04] Add encryption ops to the keyctl syscall David Härdeman
                       ` (2 preceding siblings ...)
  2006-01-24 10:58     ` David Howells
@ 2006-01-24 11:09     ` David Howells
  3 siblings, 0 replies; 17+ messages in thread
From: David Howells @ 2006-01-24 11:09 UTC (permalink / raw)
  To: David =?iso-8859-1?Q?H=E4rdeman?=; +Cc: linux-kernel, dhowells


David Härdeman <david@2gen.com> wrote:

> and adds encryption as one of the supported ops for in-kernel keys.

Do not forget to update Documentation/keys.txt.

David

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

* Re: [PATCH 04/04] Add dsa key type
  2006-01-24 11:08       ` David Howells
@ 2006-01-25 19:14         ` David Härdeman
  2006-01-26  9:41         ` David Howells
  1 sibling, 0 replies; 17+ messages in thread
From: David Härdeman @ 2006-01-25 19:14 UTC (permalink / raw)
  To: David Howells; +Cc: linux-kernel

On Tue, Jan 24, 2006 at 11:08:45AM +0000, David Howells wrote:
>David Härdeman <david@2gen.com> wrote:
>
>> Adds the dsa in-kernel key type.
>
>Please add a header file in include/keys/ to provide access to the key type
>definition and any special payload structures you use.

That was already added by one of the earlier patches as include/dsa.h 
since its shared by crypto/dsa.c and security/keys/dsa_key.c, do you 
prefer some other solution?

>> +static char *
>> +sign(const struct key_payload_dsa *skey, 
>
>Please be consistent about sticking prefixes on the names of your
>functions. This ought to be called something like dsa_sign.

Ok

>> +		printk("dsa: crypto_digest_setkey failed with error %i\n", i);
>
>Should involve KERN_ERR or something like.

Ok

Regards,
David

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

* Re: [PATCH 03/04] Add encryption ops to the keyctl syscall
  2006-01-24 10:58     ` David Howells
@ 2006-01-25 20:40       ` David Härdeman
  2006-01-26  9:43       ` David Howells
  1 sibling, 0 replies; 17+ messages in thread
From: David Härdeman @ 2006-01-25 20:40 UTC (permalink / raw)
  To: David Howells; +Cc: linux-kernel

On Tue, Jan 24, 2006 at 10:58:24AM +0000, David Howells wrote:
>> +	key = key_ref_to_ptr(key_ref);
>> +
>> +	/* see if we can read it directly */
>> +	ret = key_permission(key_ref, KEY_READ);
>
>You don't actually need to calculate key until after you've done all those
>checks, so I'd move it further down the file. You can use the function to
>release key references in the error handling or have a separate error handling
>return path.

Do you mean that I should move the key_ref_to_ptr call to right after 
the can_read_key label? If that is the case, shouldn't the same thing be 
done for keyctl_read_key?

>> +			down_read(&key->sem);
>> +			ret = key->type->encrypt(key, data, dlen, result, rlen);
>> +			up_read(&key->sem);
>
>Do we really want to restrict the key type implementor to using the r/w
>semaphore. Would it be better to let the type decide whether it wants to use
>the semaphore or let it use RCU if it so desires?

Ok, I'll move the semaphore into the dsa key type instead and change the 
appropriate comments.

Re,
David

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

* Re: [PATCH 01/04] Add multi-precision-integer maths library
  2006-01-24 10:37 ` [PATCH 01/04] Add multi-precision-integer maths library David Howells
@ 2006-01-25 20:46   ` David Härdeman
  2006-01-26  9:45   ` David Howells
  1 sibling, 0 replies; 17+ messages in thread
From: David Härdeman @ 2006-01-25 20:46 UTC (permalink / raw)
  To: David Howells; +Cc: linux-kernel

On Tue, Jan 24, 2006 at 10:37:47AM +0000, David Howells wrote:
>David Härdeman <david@2gen.com> wrote:
>
>> Adds the multi-precision-integer maths library which was originally taken
>> from GnuPG and ported to the kernel by David Howells in 2004
>> (http://people.redhat.com/~dhowells/modsign/modsign-269rc4mm1-2.diff.bz2)
>
>You should update these files from a latest Fedora, Rawhide or RHEL kernel to
>pick up the bug fixes that have been made.

Somewhat confusing...I downloaded kernel-2.6.15-1.1871_FC5.src.rpm and 
extracted linux-2.6-modsign-mpilib.patch from the srpm. After diffing 
the mpi dirs created by the previously mentioned patch and that from the 
Fedora kernel I get:

(david@austin:~/src/kernel/div)$ diff -Nurbw linux-2.6.9-rc4-mm1/crypto/mpi/ linux-902/crypto/mpi/
diff -Nurbw linux-2.6.9-rc4-mm1/crypto/mpi/mpi-div.c linux-902/crypto/mpi/mpi-div.c
--- linux-2.6.9-rc4-mm1/crypto/mpi/mpi-div.c    2006-01-24 22:56:09.000000000 +0100
+++ linux-902/crypto/mpi/mpi-div.c      2006-01-24 22:55:18.000000000 +0100
@@ -101,7 +101,7 @@
     MPI temp_divisor = NULL;
 
     if( quot == divisor || rem == divisor ) {
-       if (mpi_copy( &temp_divisor, divisor ) < 0);
+       if (mpi_copy( &temp_divisor, divisor ) < 0)
        return -ENOMEM;
        divisor = temp_divisor;
     }

Was that all the difference there was or am I missing something?

Re,
David

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

* Re: [PATCH 04/04] Add dsa key type
  2006-01-24 11:08       ` David Howells
  2006-01-25 19:14         ` David Härdeman
@ 2006-01-26  9:41         ` David Howells
  1 sibling, 0 replies; 17+ messages in thread
From: David Howells @ 2006-01-26  9:41 UTC (permalink / raw)
  To: David =?iso-8859-1?Q?H=E4rdeman?=; +Cc: David Howells, linux-kernel

David Härdeman <david@2gen.com> wrote:

> That was already added by one of the earlier patches as include/dsa.h since
> its shared by crypto/dsa.c and security/keys/dsa_key.c, do you prefer some
> other solution?

That'll do then.

David

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

* Re: [PATCH 03/04] Add encryption ops to the keyctl syscall
  2006-01-24 10:58     ` David Howells
  2006-01-25 20:40       ` David Härdeman
@ 2006-01-26  9:43       ` David Howells
  1 sibling, 0 replies; 17+ messages in thread
From: David Howells @ 2006-01-26  9:43 UTC (permalink / raw)
  To: David =?iso-8859-1?Q?H=E4rdeman?=; +Cc: David Howells, linux-kernel

David Härdeman <david@2gen.com> wrote:

> Do you mean that I should move the key_ref_to_ptr call to right after the
> can_read_key label? If that is the case, shouldn't the same thing be done for
> keyctl_read_key?

Quite possibly. I'll have a look at it when I get back from NZ. Actually, it's
possible that the compiler shifts it down anyway since it has no side effects.

David

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

* Re: [PATCH 01/04] Add multi-precision-integer maths library
  2006-01-24 10:37 ` [PATCH 01/04] Add multi-precision-integer maths library David Howells
  2006-01-25 20:46   ` David Härdeman
@ 2006-01-26  9:45   ` David Howells
  1 sibling, 0 replies; 17+ messages in thread
From: David Howells @ 2006-01-26  9:45 UTC (permalink / raw)
  To: David =?iso-8859-1?Q?H=E4rdeman?=; +Cc: David Howells, linux-kernel

David Härdeman <david@2gen.com> wrote:

> Somewhat confusing...I downloaded kernel-2.6.15-1.1871_FC5.src.rpm and
> extracted linux-2.6-modsign-mpilib.patch from the srpm. After diffing the mpi
> dirs created by the previously mentioned patch and that from the Fedora kernel
> I get:

That may be the only fix you need. Check the related patches also for overlap.

David

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

* [PATCH 04/04] Add dsa key type
  2006-01-26 21:58 [PATCH 00/04] Add DSA key type David Härdeman
@ 2006-01-26 21:58 ` David Härdeman
  0 siblings, 0 replies; 17+ messages in thread
From: David Härdeman @ 2006-01-26 21:58 UTC (permalink / raw)
  To: linux-kernel; +Cc: dhowells, keyrings, david


Adds the dsa in-kernel key type.

Signed-off-by: David Härdeman <david@2gen.com>

--
Index: dsa-kernel/security/Kconfig
===================================================================
--- dsa-kernel.orig/security/Kconfig	2006-01-25 23:39:10.000000000 +0100
+++ dsa-kernel/security/Kconfig	2006-01-25 23:42:31.000000000 +0100
@@ -21,6 +21,14 @@
 
 	  If you are unsure as to whether this is required, answer N.
 
+config KEYS_DSA_KEYS
+	tristate "Support DSA keys (EXPERIMENTAL)"
+	depends on KEYS && EXPERIMENTAL
+	select CRYPTO_MPILIB
+	select CRYPTO_DSA
+	help
+	  This option provides support for retaining DSA keys in the kernel.
+
 config KEYS_DEBUG_PROC_KEYS
 	bool "Enable the /proc/keys file by which all keys may be viewed"
 	depends on KEYS
Index: dsa-kernel/security/keys/Makefile
===================================================================
--- dsa-kernel.orig/security/keys/Makefile	2006-01-25 23:39:10.000000000 +0100
+++ dsa-kernel/security/keys/Makefile	2006-01-25 23:42:31.000000000 +0100
@@ -13,4 +13,5 @@
 	user_defined.o
 
 obj-$(CONFIG_KEYS_COMPAT) += compat.o
+obj-$(CONFIG_KEYS_DSA_KEYS) += dsa_key.o
 obj-$(CONFIG_PROC_FS) += proc.o
Index: dsa-kernel/security/keys/dsa_key.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ dsa-kernel/security/keys/dsa_key.c	2006-01-25 23:49:20.000000000 +0100
@@ -0,0 +1,376 @@
+/* dsa_key.c: DSA key
+ *
+ * Copyright (C) 2005 David Härdeman (david@2gen.com). 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+#include <linux/err.h>
+#include <asm/uaccess.h>
+#include <linux/mpi.h>
+#include <linux/dsa.h>
+#include <linux/random.h>
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+#include <keys/user-type.h>
+#include "internal.h"
+
+static int dsa_instantiate(struct key *key, const void *data, size_t datalen);
+static int dsa_update(struct key *key, const void *data, size_t datalen);
+static void dsa_destroy(struct key *key);
+static long dsa_read(const struct key *key,
+		     char __user *buffer, size_t buflen);
+static long dsa_encrypt(struct key *key,
+			const char __user *data, size_t dlen,
+			char __user *result, size_t rlen);
+
+static struct key_type key_type_dsa = {
+	.name		= "dsa",
+	.instantiate	= dsa_instantiate,
+	.update		= dsa_update,
+	.destroy	= dsa_destroy,
+	.read		= dsa_read,
+	.encrypt	= dsa_encrypt,
+	.match		= user_match,
+	.describe	= user_describe,
+};
+
+/*****************************************************************************/
+/*
+ * Signs a chunk of data using key.
+ * Returns: signature.
+ */
+static char *
+dsa_sign(const struct key_payload_dsa *skey,
+	 const void *data, size_t datalen, unsigned int *rlen)
+{
+	struct crypto_tfm *tfm;
+	char *ret = NULL;
+	u8 *sig;
+	unsigned int sigsize;
+	int i;
+	struct scatterlist sg[1];
+
+	kenter("%p, %p, %zu", skey, data, datalen);
+	tfm = crypto_alloc_tfm("dsa", 0);
+	if (!tfm)
+		goto out;
+
+	sigsize = crypto_tfm_alg_digestsize(tfm);
+	sig = kmalloc(sigsize, GFP_KERNEL);
+	if (!sig)
+		goto out_tfm;
+
+	crypto_digest_init(tfm);
+	i = crypto_digest_setkey(tfm, (const u8 *)skey, sizeof(skey));
+	if (i) {
+		printk(KERN_ERR "dsa-key: crypto_digest_setkey failed with error %i\n", i);
+		goto out_sig;
+	}
+
+	sg_init_one(sg, (u8 *)data, datalen);
+	crypto_digest_update(tfm, sg, 1);
+	crypto_digest_final(tfm, sig);
+	ret = sig;
+	*rlen = sigsize;
+	goto out_tfm;
+
+out_sig:
+	kfree(sig);
+out_tfm:
+	crypto_free_tfm(tfm);
+out:
+	return ret;
+} /* end dsa_sign() */
+
+/*****************************************************************************/
+/*
+ * Test whether the secret key is valid.
+ * Returns: if this is a valid key.
+ */
+static int dsa_check_secret_key(struct key_payload_dsa *skey)
+{
+	int rc;
+	MPI y;
+
+	/* y = g^x mod p */
+	kenter("%p", skey);
+	y = mpi_alloc(mpi_get_nlimbs(skey->part[DSA_PART_Y]));
+	rc = mpi_powm(y, skey->part[DSA_PART_G], skey->part[DSA_PART_X], skey->part[DSA_PART_P]);
+	rc = !mpi_cmp(y, skey->part[DSA_PART_Y]);
+
+	mpi_free(y);
+	return rc;
+} /* end dsa_check_secret_key() */
+
+/*****************************************************************************/
+/*
+ * create a dsa key payload
+ */
+static int dsa_create_payload(struct key_payload_dsa **payload, struct key *key,
+			      const void *data, size_t datalen)
+{
+	int ret, i;
+	unsigned int remain, read;
+	const unsigned char *ptr;
+
+	kenter("%p, %p, %p, %zu", *payload, key, data, datalen);
+	ret = -EINVAL;
+	if (datalen <= 0 || datalen > 32767 || !data)
+		goto out1;
+
+	ret = -ENOMEM;
+	*payload = kmalloc(sizeof(struct key_payload_dsa), GFP_KERNEL);
+	if (!(*payload))
+		goto out1;
+
+	ret = key_payload_reserve(key, datalen);
+	if (ret < 0)
+		goto out2;
+
+	/* read each mpi number from buffer */
+	remain = read = (unsigned int)datalen;
+	ptr = data;
+	ret = 0;
+	for (i = 0; i < DSA_PARTS; i++) {
+		kdebug("dsa-key: in loop %i, remain is %u\n", i, remain);
+		(*payload)->part[i] = mpi_read_from_buffer(ptr, &read);
+		if (!((*payload)->part[i]))
+			ret = -EINVAL;
+		ptr += read;
+		remain -= read;
+		read = remain;
+		kdebug("dsa-key: end loop\n");
+	}
+
+	if (ret < 0)
+		goto out3;
+
+	/* check validity */
+	ret = -EINVAL;
+	if(dsa_check_secret_key(*payload)) {
+		ret = 0;
+		kdebug("dsa-key: valid\n");
+		goto out1;
+	}
+
+out3:
+	printk(KERN_ERR "dsa-key: attempt to add invalid key\n");
+	for (i = 0; i < DSA_PARTS; i++)
+		mpi_free((*payload)->part[i]);
+out2:
+	kfree(*payload);
+out1:
+	return ret;
+
+} /* end dsa_instantiate() */
+
+/*****************************************************************************/
+/*
+ * instantiate a dsa key
+ */
+static int dsa_instantiate(struct key *key, const void *data, size_t datalen)
+{
+	struct key_payload_dsa *dsa_key;
+	int ret;
+
+	kenter("%p, %p, %zu", key, data, datalen);
+	ret = dsa_create_payload(&dsa_key, key, data, datalen);
+	if (ret == 0)
+		key->payload.data = dsa_key;
+
+	return ret;
+
+} /* end dsa_instantiate() */
+
+/*****************************************************************************/
+/*
+ * update a user defined key
+ */
+static int dsa_update(struct key *key, const void *data, size_t datalen)
+{
+	struct key_payload_dsa *new_payload;
+	int ret;
+
+	kenter("%p, %p, %zu", key, data, datalen);
+	ret = dsa_create_payload(&new_payload, key, data, datalen);
+	if (ret == 0) {
+		kdebug("dsa: dsa_create_payload success\n");
+		down_write(&key->sem);
+		/* this destroys the old payload, not the entire key */
+		dsa_destroy(key);
+		key->payload.data = new_payload;
+		key->expiry = 0;
+		up_write(&key->sem);
+	}
+
+	return ret;
+
+} /* end dsa_update() */
+
+/*****************************************************************************/
+/*
+ * dispose of the key payload
+ */
+static void dsa_destroy(struct key *key)
+{
+	struct key_payload_dsa *dsa_key;
+	int i;
+
+	kenter("%p", key);
+	dsa_key = key->payload.data;
+	if (dsa_key) {
+		for (i = 0; i < DSA_PARTS; i++)
+			mpi_free(dsa_key->part[i]);
+		kfree(dsa_key);
+	}
+
+} /* end dsa_destroy() */
+
+/*****************************************************************************/
+/*
+ * read the key data
+ */
+static long dsa_read(const struct key *key, char __user *buffer, size_t buflen)
+{
+	unsigned char *xbuffer[DSA_PUBLIC_PARTS];
+	unsigned nbytes[DSA_PUBLIC_PARTS];
+	unsigned nbits[DSA_PUBLIC_PARTS];
+	struct key_payload_dsa *dsa_key;
+	int i;
+	char *result, *tmp;
+	size_t reslen;
+	long ret;
+
+	kenter("%p, %p, %zu", key, buffer, buflen);
+	ret = -EINVAL;
+	dsa_key = (struct key_payload_dsa *)key->payload.data;
+	if (!dsa_key)
+		goto out1;
+
+	/* 4 x 2 bytes to store mpi sizes */
+	reslen = 8;
+	memset(xbuffer, 0, sizeof(xbuffer));
+	ret = -ENOMEM;
+
+	for (i = 0; i < DSA_PUBLIC_PARTS; i++) {
+		xbuffer[i] = mpi_get_buffer(dsa_key->part[i], &nbytes[i], NULL);
+		if (!xbuffer[i]) {
+			printk(KERN_ERR "dsa-key: failed to get mpi from buffer\n");
+			goto out2;
+		}
+		reslen += nbytes[i];
+		nbits[i] = mpi_get_nbits(dsa_key->part[i]);
+	}
+
+	result = kmalloc(reslen, GFP_KERNEL);
+	if (!result)
+		goto out2;
+
+	tmp = result;
+	for (i = 0; i < DSA_PUBLIC_PARTS; i++) {
+		kdebug("dsa-key: checking part %i\n", i);
+		kdebug("dsa-key: nbytes is %i, nbits is %i, topbyte is %2hx, botbyte is %2hx\n",
+			nbytes[i], nbits[i], ((nbits[i] >> 8) & 0xff), ((nbits[i]) & 0xff));
+		MPI_WSIZE(tmp, nbits[i]);
+		memcpy(tmp, xbuffer[i], nbytes[i]);
+		tmp += nbytes[i];
+	}
+
+	ret = -EFAULT;
+	if (copy_to_user(buffer, result, min(reslen, buflen)) == 0)
+		ret = reslen;
+
+	memset(result, 0, reslen);
+	kfree(result);
+
+out2:
+	for (i = 0; i < DSA_PUBLIC_PARTS; i++) {
+		memset(xbuffer[i], 0, nbytes[i]);
+		kfree(xbuffer[i]);
+	}
+out1:
+	return ret;
+
+} /* end dsa_read() */
+
+/*****************************************************************************/
+/*
+ * encrypt data using a key
+ */
+static long dsa_encrypt(struct key *key,
+			const char __user *data, size_t dlen,
+			char __user *result, size_t rlen)
+{
+	char *signature;
+	char *inbuf;
+	long ret;
+	size_t siglen = 0;
+
+	kenter("%p, %p, %zu, %p, %zu", key, data, dlen, result, rlen);
+	down_read(&key->sem);
+	ret = -ENOMEM;
+	inbuf = kmalloc(dlen, GFP_KERNEL);
+	if (!inbuf)
+		goto out1;
+
+	ret = -EFAULT;
+	/* pull the data to sign into kernel space */
+	if (copy_from_user(inbuf, data, dlen))
+		goto out2;
+
+	/* sign it */
+	signature = dsa_sign((struct key_payload_dsa *)key->payload.data,
+			 inbuf, dlen, &siglen);
+	if (!signature)
+		goto out2;
+
+	/* push the result to userspace */
+	if(copy_to_user(result, signature, min(rlen, siglen)) == 0)
+		ret = siglen;
+
+	memset(signature, 0, siglen);
+	kfree(signature);
+out2:
+	memset(inbuf, 0, dlen);
+	kfree(inbuf);
+out1:
+	up_read(&key->sem);
+	return ret;
+} /* end dsa_encrypt() */
+
+static int __init dsa_init(void)
+{
+	int ret;
+
+	ret = register_key_type(&key_type_dsa);
+	if (ret < 0)
+		printk(KERN_ERR "dsa-key: failed to register key type\n");
+	else
+		printk(KERN_INFO "dsa-key: new key type registered\n");
+
+	return ret;
+}
+
+static void __exit dsa_exit (void)
+{
+	printk(KERN_INFO "dsa-key: unregistering key type\n");
+	unregister_key_type(&key_type_dsa);
+}
+
+module_init(dsa_init);
+module_exit(dsa_exit);
+
+MODULE_AUTHOR("David Härdeman");
+MODULE_DESCRIPTION("DSA key support");
+MODULE_LICENSE("GPL");


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

end of thread, other threads:[~2006-01-26 21:59 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <11380489522552@2gen.com>
2006-01-23 20:42 ` [PATCH 02/04] Add dsa crypto ops David Härdeman
2006-01-23 20:42   ` [PATCH 03/04] Add encryption ops to the keyctl syscall David Härdeman
2006-01-23 20:42     ` [PATCH 04/04] Add dsa key type David Härdeman
2006-01-24 11:08       ` David Howells
2006-01-25 19:14         ` David Härdeman
2006-01-26  9:41         ` David Howells
2006-01-24  4:33     ` [PATCH 03/04] Add encryption ops to the keyctl syscall Randy.Dunlap
2006-01-24 10:58     ` David Howells
2006-01-25 20:40       ` David Härdeman
2006-01-26  9:43       ` David Howells
2006-01-24 11:09     ` David Howells
2006-01-24  1:22   ` [PATCH 02/04] Add dsa crypto ops Herbert Xu
2006-01-24  6:49     ` David Härdeman
2006-01-24 10:37 ` [PATCH 01/04] Add multi-precision-integer maths library David Howells
2006-01-25 20:46   ` David Härdeman
2006-01-26  9:45   ` David Howells
2006-01-26 21:58 [PATCH 00/04] Add DSA key type David Härdeman
2006-01-26 21:58 ` [PATCH 04/04] Add dsa " David Härdeman

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