From: "David Härdeman" <david@2gen.com>
To: linux-kernel@vger.kernel.org
Cc: dhowells@redhat.com, keyrings@linux-nfs.org, david@2gen.com
Subject: [PATCH 04/04] Add dsa key type
Date: Thu, 26 Jan 2006 22:58:16 +0100 [thread overview]
Message-ID: <1138312696814@2gen.com> (raw)
In-Reply-To: <1138312694656@2gen.com>
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");
next prev parent reply other threads:[~2006-01-26 21:59 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-01-26 21:58 [PATCH 00/04] Add DSA key type David Härdeman
2006-01-26 21:58 ` [PATCH 01/04] Add multi-precision-integer maths library David Härdeman
2006-01-27 9:28 ` Christoph Hellwig
2006-01-27 20:07 ` David Howells
2006-01-27 20:41 ` David Härdeman
2006-01-27 22:19 ` [Keyrings] " Trond Myklebust
2006-01-27 23:35 ` Kyle Moffett
2006-01-28 0:27 ` Adrian Bunk
2006-01-28 3:45 ` Trond Myklebust
2006-01-28 7:17 ` Kyle Moffett
2006-01-28 10:39 ` Adrian Bunk
2006-01-28 0:22 ` Adrian Bunk
2006-01-28 10:46 ` David Härdeman
2006-01-28 13:03 ` Adrian Bunk
2006-01-28 17:09 ` David Härdeman
2006-01-28 16:37 ` [Keyrings] " Trond Myklebust
2006-01-28 16:57 ` David Härdeman
2006-01-29 3:20 ` Trond Myklebust
2006-01-29 11:33 ` David Härdeman
2006-01-29 12:29 ` Adrian Bunk
2006-01-29 13:09 ` Arjan van de Ven
2006-01-29 20:05 ` Steve French
2006-01-29 20:52 ` Arjan van de Ven
2006-01-29 21:41 ` Steve French
2006-02-06 12:31 ` David Howells
2006-01-29 23:18 ` Adrian Bunk
2006-01-29 13:18 ` David Härdeman
2006-01-29 23:36 ` Adrian Bunk
2006-01-30 18:09 ` Nix
2006-01-29 16:38 ` Trond Myklebust
2006-01-29 18:49 ` Dax Kelson
2006-01-29 19:10 ` Trond Myklebust
2006-01-29 21:29 ` David Härdeman
2006-01-29 21:46 ` Trond Myklebust
2006-01-29 21:13 ` David Härdeman
2006-01-29 21:28 ` Trond Myklebust
2006-01-29 22:02 ` David Härdeman
2006-01-29 22:05 ` Trond Myklebust
2006-01-29 22:54 ` Kyle Moffett
2006-01-29 23:07 ` Trond Myklebust
2006-01-29 23:15 ` Adrian Bunk
2006-01-29 21:09 ` Pavel Machek
2006-01-26 21:58 ` [PATCH 03/04] Add encryption ops to the keyctl syscall David Härdeman
2006-01-26 21:58 ` [PATCH 02/04] Add dsa crypto ops David Härdeman
2006-01-26 21:58 ` David Härdeman [this message]
2006-01-27 1:10 ` [PATCH 00/04] Add DSA key type Herbert Xu
2006-01-27 7:18 ` David Härdeman
2006-01-27 20:11 ` David Howells
2006-01-27 23:22 ` Herbert Xu
-- strict thread matches above, loose matches on Subject: below --
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1138312696814@2gen.com \
--to=david@2gen.com \
--cc=dhowells@redhat.com \
--cc=keyrings@linux-nfs.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.