* [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
* [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 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
* 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 0 siblings, 1 reply; 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 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 0 siblings, 1 reply; 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 04/04] Add dsa key type 2006-01-25 19:14 ` David Härdeman @ 2006-01-26 9:41 ` David Howells 0 siblings, 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-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 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-24 11:09 ` David Howells 3 siblings, 1 reply; 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 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 0 siblings, 1 reply; 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 03/04] Add encryption ops to the keyctl syscall 2006-01-25 20:40 ` David Härdeman @ 2006-01-26 9:43 ` David Howells 0 siblings, 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 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 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 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 1 sibling, 1 reply; 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 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 0 siblings, 1 reply; 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 01/04] Add multi-precision-integer maths library 2006-01-25 20:46 ` David Härdeman @ 2006-01-26 9:45 ` David Howells 0 siblings, 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 00/04] Add DSA key type @ 2006-01-26 21:58 David Härdeman 2006-01-26 21:58 ` [PATCH 04/04] Add dsa " David Härdeman 0 siblings, 1 reply; 17+ messages in thread From: David Härdeman @ 2006-01-26 21:58 UTC (permalink / raw) To: linux-kernel; +Cc: dhowells, keyrings, david The following four patches add support for DSA keys to the in-kernel key management system. In-kernel dsa keys allows a process to use the request_key mechanism to request such keys on demand. One such example is a backup script that, when done, could issue a request for an appropriate ssh key. The request would then be forwarded by /sbin/request-key to the appropriate user who could supply the key which is in turn used by the backup script to transfer the results to a backup server. This allows for much more flexible and interesting solutions than passwordless ssh key files or shared ssh agents would ever be able to support. (I have a separate patch for openssh which allows ssh-add and ssh to work with in-kernel keys). In addition, the in-kernel keys have the advantage of being non-ptraceable, will not be swapped out to disk, and does not run the risk of being included in coredumps. The functionality added by these patches should also be interesting to some other security features (such as signed modules, signed binaries and possibly some encrypted filesystems). The patch is split into four sub-patches: 1) Adds a multi-precision-integer maths library 2) Adds dsa cryptographic operations. Since a dsa signature is always two 160-bit integer, I've modeled the dsa crypto as a hash algorithm. 3) Adds encryption as one of the supported ops for in-kernel keys. 4) Adds the dsa in-kernel key type. This is the second version of these patches with the following changes from the first version: * Make sure all functions have proper dsa_ prefixes * Use kenter/kleave/kdebug in dsa_key.c instead of duplicated versions * Let key type decide which locking to use for encrypt ops (semaphore or rcu) * Add KERN_XXX levels for printk's * Merge newer mpilib from Fedora kernel 2.6.15-1.1871_FC5 * Change some non-tab whitespace to tabs * Change mpilib exports from EXPORT_SYMBOL to EXPORT_SYMBOL_GPL * Change crypto/dsa.c to copy key instead of referencing it * Add documentation Regards, David Härdeman -- Documentation/keys.txt | 77 + crypto/Kconfig | 15 crypto/Makefile | 2 crypto/dsa.c | 265 ++++++ crypto/mpi/Makefile | 31 crypto/mpi/generic_mpi-asm-defs.h | 10 crypto/mpi/generic_mpih-add1.c | 64 + crypto/mpi/generic_mpih-lshift.c | 66 + crypto/mpi/generic_mpih-mul1.c | 60 + crypto/mpi/generic_mpih-mul2.c | 63 + crypto/mpi/generic_mpih-mul3.c | 64 + crypto/mpi/generic_mpih-rshift.c | 66 + crypto/mpi/generic_mpih-sub1.c | 63 + crypto/mpi/generic_udiv-w-sdiv.c | 108 ++ crypto/mpi/longlong.h | 1502 ++++++++++++++++++++++++++++++++++++++ crypto/mpi/mpi-add.c | 241 ++++++ crypto/mpi/mpi-bit.c | 240 ++++++ crypto/mpi/mpi-cmp.c | 70 + crypto/mpi/mpi-div.c | 342 ++++++++ crypto/mpi/mpi-gcd.c | 62 + crypto/mpi/mpi-inline.c | 32 crypto/mpi/mpi-inline.h | 128 +++ crypto/mpi/mpi-internal.h | 265 ++++++ crypto/mpi/mpi-inv.c | 189 ++++ crypto/mpi/mpi-mpow.c | 136 +++ crypto/mpi/mpi-mul.c | 199 +++++ crypto/mpi/mpi-pow.c | 324 ++++++++ crypto/mpi/mpi-scan.c | 127 +++ crypto/mpi/mpicoder.c | 388 +++++++++ crypto/mpi/mpih-cmp.c | 58 + crypto/mpi/mpih-div.c | 545 +++++++++++++ crypto/mpi/mpih-mul.c | 537 +++++++++++++ crypto/mpi/mpiutil.c | 224 +++++ include/linux/compat.h | 4 include/linux/dsa.h | 33 include/linux/key.h | 10 include/linux/keyctl.h | 1 include/linux/mpi.h | 154 +++ include/linux/syscalls.h | 5 security/Kconfig | 8 security/keys/Makefile | 1 security/keys/compat.c | 9 security/keys/dsa_key.c | 376 +++++++++ security/keys/keyctl.c | 67 + 44 files changed, 7221 insertions(+), 10 deletions(-) ^ 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