diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/userspace/Makefile | 2 | ||||
-rw-r--r-- | crypto/userspace/cryptodev_cipher.c | 19 | ||||
-rw-r--r-- | crypto/userspace/cryptodev_int.h | 2 | ||||
-rw-r--r-- | crypto/userspace/cryptodev_main.c | 49 | ||||
-rw-r--r-- | crypto/userspace/ncr-dh.c | 282 | ||||
-rw-r--r-- | crypto/userspace/ncr-dh.h | 25 | ||||
-rw-r--r-- | crypto/userspace/ncr-int.h | 9 | ||||
-rw-r--r-- | crypto/userspace/ncr-key-storage.c | 21 | ||||
-rw-r--r-- | crypto/userspace/ncr-key-wrap.c | 23 | ||||
-rw-r--r-- | crypto/userspace/ncr-key.c | 108 | ||||
-rw-r--r-- | crypto/userspace/ncr-limits.c | 21 | ||||
-rw-r--r-- | crypto/userspace/ncr-pk.c | 189 | ||||
-rw-r--r-- | crypto/userspace/ncr-pk.h | 5 | ||||
-rw-r--r-- | crypto/userspace/ncr-sessions.c | 118 | ||||
-rw-r--r-- | crypto/userspace/ncr.c | 27 |
15 files changed, 718 insertions, 182 deletions
diff --git a/crypto/userspace/Makefile b/crypto/userspace/Makefile index 41c82c42e6a..0e3354053d3 100644 --- a/crypto/userspace/Makefile +++ b/crypto/userspace/Makefile @@ -67,7 +67,7 @@ TOMCRYPT_OBJECTS = libtomcrypt/misc/zeromem.o libtomcrypt/misc/crypt/crypt_argch libtomcrypt/pk/asn1/der/x509/der_decode_subject_public_key_info.o cryptodev-objs = cryptodev_main.o cryptodev_cipher.o ncr.o \ - ncr-key.o ncr-limits.o ncr-pk.o ncr-sessions.o \ + ncr-key.o ncr-limits.o ncr-pk.o ncr-sessions.o ncr-dh.o \ ncr-key-wrap.o ncr-key-storage.o $(TOMMATH_OBJECTS) \ $(TOMCRYPT_OBJECTS) diff --git a/crypto/userspace/cryptodev_cipher.c b/crypto/userspace/cryptodev_cipher.c index 0dd0db77120..01dc29dc7cc 100644 --- a/crypto/userspace/cryptodev_cipher.c +++ b/crypto/userspace/cryptodev_cipher.c @@ -2,21 +2,24 @@ * Driver for /dev/crypto device (aka CryptoDev) * * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org> + * Portions Copyright (c) 2010 Michael Weiser + * Portions Copyright (c) 2010 Phil Sutter * * This file is part of linux cryptodev. * - * cryptodev 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 3 of the License, or - * (at your option) any later version. - * - * cryptodev is distributed in the hope that it will be useful, + * 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. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <linux/crypto.h> diff --git a/crypto/userspace/cryptodev_int.h b/crypto/userspace/cryptodev_int.h index 3c6eca475a2..b4059febbb0 100644 --- a/crypto/userspace/cryptodev_int.h +++ b/crypto/userspace/cryptodev_int.h @@ -25,7 +25,7 @@ extern int cryptodev_verbosity; /* For zero copy */ -int __get_userbuf(uint8_t *addr, uint32_t len, int write, +int __get_userbuf(uint8_t __user *addr, uint32_t len, int write, int pgcount, struct page **pg, struct scatterlist *sg); void release_user_pages(struct page **pg, int pagecount); diff --git a/crypto/userspace/cryptodev_main.c b/crypto/userspace/cryptodev_main.c index 7ed09116e25..19dc6773df3 100644 --- a/crypto/userspace/cryptodev_main.c +++ b/crypto/userspace/cryptodev_main.c @@ -6,18 +6,19 @@ * * This file is part of linux cryptodev. * - * cryptodev 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 3 of the License, or - * (at your option) any later version. - * - * cryptodev is distributed in the hope that it will be useful, + * 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. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* @@ -447,7 +448,7 @@ static int __crypto_run_std(struct csession *ses_ptr, struct crypt_op *cop) { char *data; - char __user *src, __user *dst; + char __user *src, *dst; struct scatterlist sg; size_t nbytes, bufsize; int ret = 0; @@ -509,7 +510,7 @@ void release_user_pages(struct page **pg, int pagecount) #define PAGEOFFSET(buf) ((unsigned long)buf & ~PAGE_MASK) /* fetch the pages addr resides in into pg and initialise sg with them */ -int __get_userbuf(uint8_t *addr, uint32_t len, int write, +int __get_userbuf(uint8_t __user *addr, uint32_t len, int write, int pgcount, struct page **pg, struct scatterlist *sg) { int ret, pglen, i = 0; @@ -561,19 +562,27 @@ static int get_userbuf(struct csession *ses, (*tot_pages) = pagecount = src_pagecount + dst_pagecount; if (pagecount > ses->array_size) { - while (ses->array_size < pagecount) - ses->array_size *= 2; + struct scatterlist *sg; + struct page **pages; + int array_size; - dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n", - __func__, ses->array_size); - ses->pages = krealloc(ses->pages, ses->array_size * - sizeof(struct page *), GFP_KERNEL); - ses->sg = krealloc(ses->sg, ses->array_size * - sizeof(struct scatterlist), GFP_KERNEL); + for (array_size = ses->array_size; array_size < pagecount; + array_size *= 2) + ; - if (ses->sg == NULL || ses->pages == NULL) { + dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n", + __func__, array_size); + pages = krealloc(ses->pages, array_size * sizeof(struct page *), + GFP_KERNEL); + if (pages == NULL) return -ENOMEM; - } + ses->pages = pages; + sg = krealloc(ses->sg, array_size * sizeof(struct scatterlist), + GFP_KERNEL); + if (sg == NULL) + return -ENOMEM; + ses->sg = sg; + ses->array_size = array_size; } if (__get_userbuf(cop->src, cop->len, write_src, diff --git a/crypto/userspace/ncr-dh.c b/crypto/userspace/ncr-dh.c new file mode 100644 index 00000000000..f14e131a042 --- /dev/null +++ b/crypto/userspace/ncr-dh.c @@ -0,0 +1,282 @@ +/* + * New driver for /dev/crypto device (aka CryptoDev) + + * Copyright (c) 2010 Katholieke Universiteit Leuven + * + * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org> + * + * This file is part of linux cryptodev. + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <linux/mm.h> +#include <linux/random.h> +#include "cryptodev.h" +#include <asm/uaccess.h> +#include <asm/ioctl.h> +#include <linux/scatterlist.h> +#include <ncr.h> +#include <ncr-int.h> +#include <tomcrypt.h> +#include <ncr-dh.h> + +void dh_free(dh_key * key) +{ + mp_clear_multi(&key->p, &key->g, &key->x, NULL); +} + +int dh_import_params(dh_key * key, uint8_t * p, size_t p_size, uint8_t * g, + size_t g_size) +{ + int ret; + int err; + + if ((err = + mp_init_multi(&key->p, &key->g, &key->x, &key->y, + NULL)) != CRYPT_OK) { + err(); + return -ENOMEM; + } + + if ((err = + mp_read_unsigned_bin(&key->p, (unsigned char *) p, + p_size)) != CRYPT_OK) { + err(); + ret = _ncr_tomerr(err); + goto fail; + } + + if ((err = + mp_read_unsigned_bin(&key->g, (unsigned char *) g, + g_size)) != CRYPT_OK) { + err(); + ret = _ncr_tomerr(err); + goto fail; + } + + return 0; + fail: + mp_clear_multi(&key->p, &key->g, &key->x, &key->y, NULL); + + return ret; +} + +int dh_generate_key(dh_key * key) +{ + void *buf; + int size; + int err, ret; + + size = mp_unsigned_bin_size(&key->p); + if (size == 0) { + err(); + return -EINVAL; + } + + buf = kmalloc(size, GFP_KERNEL); + if (buf == NULL) { + err(); + return -ENOMEM; + } + + get_random_bytes(buf, size); + + if ((err = mp_read_unsigned_bin(&key->x, buf, size)) != CRYPT_OK) { + err(); + ret = _ncr_tomerr(err); + goto fail; + } + + err = mp_mod(&key->x, &key->p, &key->x); + if (err != CRYPT_OK) { + err(); + ret = _ncr_tomerr(err); + goto fail; + } + + key->type = PK_PRIVATE; + + ret = 0; + fail: + kfree(buf); + + return ret; + +} + +int dh_generate_public(dh_key * public, dh_key * private) +{ + int err, ret; + + err = + mp_exptmod(&private->g, &private->x, &private->p, &public->y); + if (err != CRYPT_OK) { + err(); + ret = _ncr_tomerr(err); + goto fail; + } + + public->type = PK_PUBLIC; + + ret = 0; + fail: + + return ret; +} + +int dh_export(uint8_t * out, unsigned long * outlen, int type, dh_key * key) +{ + unsigned long zero = 0; + int err; + + if (out == NULL || outlen == NULL || key == NULL) { + err(); + return -EINVAL; + } + + /* can we store the static header? */ + if (type == PK_PRIVATE && key->type != PK_PRIVATE) { + return -EINVAL; + } + + if (type != PK_PUBLIC && type != PK_PRIVATE) { + return -EINVAL; + } + + /* This encoding is different from the one in original + * libtomcrypt. It uses a compatible encoding with gnutls + * and openssl + */ + if (type == PK_PRIVATE) { + err = der_encode_sequence_multi(out, outlen, + LTC_ASN1_SHORT_INTEGER, 1UL, &zero, + LTC_ASN1_INTEGER, 1UL, &key->p, + LTC_ASN1_INTEGER, 1UL, &key->g, + LTC_ASN1_INTEGER, 1UL, &key->x, + LTC_ASN1_EOL, 0UL, NULL); + } else { + err = mp_unsigned_bin_size(&key->y); + if (err > *outlen) { + err(); + return -EOVERFLOW; + } + + *outlen = err; + + err = mp_to_unsigned_bin(&key->y, out); + } + + if (err != CRYPT_OK) { + err(); + return _ncr_tomerr(err); + } + + return 0; +} + +int dh_import(const uint8_t * in, size_t inlen, dh_key * key) +{ + int err; + unsigned long zero = 0; + + if (in == NULL || key == NULL) { + err(); + return -EINVAL; + } + + /* init key */ + if (mp_init_multi + (&key->p, &key->g, &key->x, &key->y, NULL) != CRYPT_OK) { + return -ENOMEM; + } + + /* get key type */ + if ((err = der_decode_sequence_multi(in, inlen, + LTC_ASN1_SHORT_INTEGER, 1UL, &zero, + LTC_ASN1_INTEGER, 1UL, &key->p, + LTC_ASN1_INTEGER, 1UL, &key->g, + LTC_ASN1_INTEGER, 1UL, &key->x, + LTC_ASN1_EOL, 0UL, NULL)) == CRYPT_OK) { + key->type = PK_PRIVATE; + } else { /* public */ + err = mp_read_unsigned_bin(&key->y, in, inlen); + key->type = PK_PUBLIC; + } + + if (err != CRYPT_OK) { + goto LBL_ERR; + } + + return 0; + + LBL_ERR: + mp_clear_multi(&key->p, &key->g, &key->x, &key->y, NULL); + return _ncr_tomerr(err); +} + +int dh_derive_gxy(struct key_item_st* newkey, dh_key * key, + void* pk, size_t pk_size) +{ +int ret, err; +mp_int y, gxy; + /* newkey will be a secret key with value of g^{xy} + */ + + if (mp_init_multi(&y, &gxy, NULL) != CRYPT_OK) { + err(); + return -ENOMEM; + } + + if (key->type != PK_PRIVATE) { + err(); + return -EINVAL; + } + + if ((err=mp_read_unsigned_bin(&y, pk, pk_size)) != CRYPT_OK) { + err(); + ret = _ncr_tomerr(err); + goto fail; + } + + if ((err=mp_exptmod(&y, &key->x, &key->p, &gxy))!= CRYPT_OK) { + err(); + ret = _ncr_tomerr(err); + goto fail; + } + + err = mp_unsigned_bin_size(&gxy); + if (err > NCR_CIPHER_MAX_KEY_LEN) { + err(); + ret = -EOVERFLOW; + goto fail; + } + newkey->key.secret.size = err; + + err = mp_to_unsigned_bin(&gxy, newkey->key.secret.data); + if (err != CRYPT_OK) { + err(); + ret = _ncr_tomerr(err); + goto fail; + } + + newkey->type = NCR_KEY_TYPE_SECRET; + + ret = 0; +fail: + mp_clear_multi(&y, &gxy, NULL); + + return ret; +} diff --git a/crypto/userspace/ncr-dh.h b/crypto/userspace/ncr-dh.h new file mode 100644 index 00000000000..cc45d3206cc --- /dev/null +++ b/crypto/userspace/ncr-dh.h @@ -0,0 +1,25 @@ +#ifndef NCR_DH_H +# define NCR_DH_H + +#include <tomcrypt.h> + +typedef struct { + int type; /* PK_PRIVATE or PK_PUBLIC */ + mp_int p; + mp_int g; + mp_int x; /* private */ + mp_int y; /* public: y=g^x */ +} dh_key; + +int dh_generate_key(dh_key * key); +int dh_import_params(dh_key * key, uint8_t* p, size_t p_size, uint8_t* g, size_t g_size); +void dh_free(dh_key * key); +int dh_generate_public(dh_key * public, dh_key* private); + +int dh_export(uint8_t *out, unsigned long *outlen, int type, dh_key *key); +int dh_import(const uint8_t *in, size_t inlen, dh_key *key); + +int dh_derive_gxy(struct key_item_st* newkey, dh_key * key, + void* pk, size_t pk_size); + +#endif diff --git a/crypto/userspace/ncr-int.h b/crypto/userspace/ncr-int.h index 03fab19a0bd..2af794f41d3 100644 --- a/crypto/userspace/ncr-int.h +++ b/crypto/userspace/ncr-int.h @@ -5,6 +5,7 @@ #include <asm/atomic.h> #include "cryptodev_int.h" #include <ncr-pk.h> +#include <ncr-dh.h> #define KEY_DATA_MAX_SIZE 3*1024 @@ -18,6 +19,7 @@ struct algo_properties_st { unsigned can_sign:1; unsigned can_digest:1; unsigned can_encrypt:1; + unsigned can_kx:1; /* key exchange */ unsigned is_symmetric:1; unsigned is_pk:1; int digest_size; @@ -73,6 +75,7 @@ struct key_item_st { union { rsa_key rsa; dsa_key dsa; + dh_key dh; } pk; } key; @@ -107,7 +110,11 @@ void ncr_deinit_lists(struct ncr_lists *lst); int ncr_ioctl(struct ncr_lists*, struct file *filp, unsigned int cmd, unsigned long arg); - + +/* key derivation */ +int ncr_key_derive(struct list_sem_st* key_lst, void __user* arg); + +/* key handling */ int ncr_key_init(struct list_sem_st*, void __user* arg); int ncr_key_deinit(struct list_sem_st*, void __user* arg); int ncr_key_export(struct list_sem_st* key_lst,void __user* arg); diff --git a/crypto/userspace/ncr-key-storage.c b/crypto/userspace/ncr-key-storage.c index a1788dc4f97..ef20965fc1e 100644 --- a/crypto/userspace/ncr-key-storage.c +++ b/crypto/userspace/ncr-key-storage.c @@ -1,22 +1,25 @@ /* * New driver for /dev/crypto device (aka CryptoDev) - * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org> + * Copyright (c) 2010 Katholieke Universiteit Leuven * - * This file is part of linux cryptodev. + * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org> * - * cryptodev 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 3 of the License, or - * (at your option) any later version. + * This file is part of linux cryptodev. * - * cryptodev is distributed in the hope that it will be useful, + * 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. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <linux/mm.h> diff --git a/crypto/userspace/ncr-key-wrap.c b/crypto/userspace/ncr-key-wrap.c index 2edcefb78e6..5d3ec675b6c 100644 --- a/crypto/userspace/ncr-key-wrap.c +++ b/crypto/userspace/ncr-key-wrap.c @@ -1,22 +1,25 @@ /* * New driver for /dev/crypto device (aka CryptoDev) - * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org> + * Copyright (c) 2010 Katholieke Universiteit Leuven * - * This file is part of linux cryptodev. + * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org> * - * cryptodev 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 3 of the License, or - * (at your option) any later version. + * This file is part of linux cryptodev. * - * cryptodev is distributed in the hope that it will be useful, + * 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. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <linux/mm.h> @@ -222,7 +225,7 @@ size_t size; if (ret < 0) { err(); kfree(R); - return ret; + goto cleanup; } if (memcmp(A, iv, 4)!= 0) { diff --git a/crypto/userspace/ncr-key.c b/crypto/userspace/ncr-key.c index 9e67b5246a7..e0361bc8f83 100644 --- a/crypto/userspace/ncr-key.c +++ b/crypto/userspace/ncr-key.c @@ -1,22 +1,25 @@ /* * New driver for /dev/crypto device (aka CryptoDev) - - * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org> * - * This file is part of linux cryptodev. + * Copyright (c) 2010 Katholieke Universiteit Leuven * - * cryptodev 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 3 of the License, or - * (at your option) any later version. + * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org> * - * cryptodev is distributed in the hope that it will be useful, + * This file is part of linux cryptodev. + * + * 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. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <linux/mm.h> @@ -273,6 +276,7 @@ int ret; goto fail; } } + data.idata_size = item->key.secret.size; break; case NCR_KEY_TYPE_PUBLIC: @@ -343,7 +347,9 @@ size_t tmp_size; err(); return ret; } - + + ncr_key_clear(item); + tmp = kmalloc(data.idata_size, GFP_KERNEL); if (tmp == NULL) { err(); @@ -423,6 +429,9 @@ static void ncr_key_clear(struct key_item_st* item) ncr_pk_clear(item); } memset(&item->key, 0, sizeof(item->key)); + memset(item->key_id, 0, sizeof(item->key_id)); + item->key_id_size = 0; + item->flags = 0; return; } @@ -459,8 +468,7 @@ size_t size; } item->type = algo->key_type; if (item->type == NCR_KEY_TYPE_SECRET) { - /* arbitrary */ - item->algorithm = _ncr_algo_to_properties(NCR_ALG_AES_CBC); + item->algorithm = algo; size = gen.params.params.secret.bits/8; if ((gen.params.params.secret.bits % 8 != 0) || @@ -508,14 +516,23 @@ int ret; err(); return ret; } + + if (item->type == NCR_KEY_TYPE_INVALID) { + err(); + ret = -EINVAL; + goto fail; + } info.flags = item->flags; info.type = item->type; info.algorithm = item->algorithm->algo; + + ret = 0; +fail: _ncr_key_item_put( item); - return 0; + return ret; } int ncr_key_generate_pair(struct list_sem_st* lst, void __user* arg) @@ -582,13 +599,64 @@ fail: return ret; } -int ncr_key_derive(struct list_sem_st* lst, void __user* arg) +/* "exports" a key to a data item. If the key is not exportable + * to userspace then the data item will also not be. + */ +int ncr_key_derive(struct list_sem_st* key_lst, void __user* arg) { - return -EINVAL; -} +struct ncr_key_derivation_params_st data; +int ret; +struct key_item_st* key = NULL; +struct key_item_st* newkey = NULL; -int ncr_key_get_public(struct list_sem_st* lst, void __user* arg) -{ - return -EINVAL; + if (unlikely(copy_from_user(&data, arg, sizeof(data)))) { + err(); + return -EFAULT; + } + + ret = ncr_key_item_get_read( &key, key_lst, data.key); + if (ret < 0) { + err(); + return ret; + } + + ret = ncr_key_item_get_write( &newkey, key_lst, data.newkey); + if (ret < 0) { + err(); + goto fail; + } + + ncr_key_clear(newkey); + + newkey->flags = data.keyflags; + + switch (key->type) { + case NCR_KEY_TYPE_PUBLIC: + case NCR_KEY_TYPE_PRIVATE: + ret = ncr_pk_derive(newkey, key, &data); + if (ret < 0) { + err(); + goto fail; + } + break; + default: + err(); + ret = -EINVAL; + goto fail; + } + + if (unlikely(copy_to_user(arg, &data, sizeof(data)))) { + err(); + ret = -EFAULT; + } else + ret = 0; + +fail: + if (key) + _ncr_key_item_put(key); + if (newkey) + _ncr_key_item_put(newkey); + return ret; + } diff --git a/crypto/userspace/ncr-limits.c b/crypto/userspace/ncr-limits.c index 7a98f3c4f38..bbcd1e95e6e 100644 --- a/crypto/userspace/ncr-limits.c +++ b/crypto/userspace/ncr-limits.c @@ -1,22 +1,25 @@ /* * New driver for /dev/crypto device (aka CryptoDev) - * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org> + * Copyright (c) 2010 Katholieke Universiteit Leuven * - * This file is part of linux cryptodev. + * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org> * - * cryptodev 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 3 of the License, or - * (at your option) any later version. + * This file is part of linux cryptodev. * - * cryptodev is distributed in the hope that it will be useful, + * 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. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <linux/types.h> diff --git a/crypto/userspace/ncr-pk.c b/crypto/userspace/ncr-pk.c index ecb2ce3f5b0..e4529b30d7f 100644 --- a/crypto/userspace/ncr-pk.c +++ b/crypto/userspace/ncr-pk.c @@ -1,22 +1,25 @@ /* * New driver for /dev/crypto device (aka CryptoDev) - * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org> + * Copyright (c) 2010 Katholieke Universiteit Leuven * - * This file is part of linux cryptodev. + * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org> * - * cryptodev 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 3 of the License, or - * (at your option) any later version. + * This file is part of linux cryptodev. * - * cryptodev is distributed in the hope that it will be useful, + * 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. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <linux/mm.h> @@ -31,7 +34,7 @@ static struct workqueue_struct * pk_wq = NULL; -static int tomerr(int err) +int _ncr_tomerr(int err) { switch (err) { case CRYPT_BUFFER_OVERFLOW: @@ -54,6 +57,9 @@ void ncr_pk_clear(struct key_item_st* key) case NCR_ALG_DSA: dsa_free(&key->key.pk.dsa); break; + case NCR_ALG_DH: + dh_free(&key->key.pk.dh); + break; default: return; } @@ -78,14 +84,14 @@ static int ncr_pk_make_public_and_id( struct key_item_st * private, struct key_i cret = rsa_export(tmp, &max_size, PK_PUBLIC, &private->key.pk.rsa); if (cret != CRYPT_OK) { err(); - ret = tomerr(cret); + ret = _ncr_tomerr(cret); goto fail; } cret = rsa_import(tmp, max_size, &public->key.pk.rsa); if (cret != CRYPT_OK) { err(); - ret = tomerr(cret); + ret = _ncr_tomerr(cret); goto fail; } break; @@ -93,14 +99,21 @@ static int ncr_pk_make_public_and_id( struct key_item_st * private, struct key_i cret = dsa_export(tmp, &max_size, PK_PUBLIC, &private->key.pk.dsa); if (cret != CRYPT_OK) { err(); - ret = tomerr(cret); + ret = _ncr_tomerr(cret); goto fail; } cret = dsa_import(tmp, max_size, &public->key.pk.dsa); if (cret != CRYPT_OK) { err(); - ret = tomerr(cret); + ret = _ncr_tomerr(cret); + goto fail; + } + break; + case NCR_ALG_DH: + ret = dh_generate_public(&public->key.pk.dh, &private->key.pk.dh); + if (ret < 0) { + err(); goto fail; } break; @@ -114,7 +127,7 @@ static int ncr_pk_make_public_and_id( struct key_item_st * private, struct key_i cret = hash_memory(_ncr_algo_to_properties(NCR_ALG_SHA1), tmp, max_size, private->key_id, &key_id_size); if (cret != CRYPT_OK) { err(); - ret = tomerr(cret); + ret = _ncr_tomerr(cret); goto fail; } private->key_id_size = public->key_id_size = key_id_size; @@ -130,7 +143,7 @@ fail: int ncr_pk_pack( const struct key_item_st * key, uint8_t * packed, uint32_t * packed_size) { unsigned long max_size = *packed_size; - int cret; + int cret, ret; if (packed == NULL || packed_size == NULL) { err(); @@ -143,7 +156,7 @@ int ncr_pk_pack( const struct key_item_st * key, uint8_t * packed, uint32_t * pa if (cret != CRYPT_OK) { *packed_size = max_size; err(); - return tomerr(cret); + return _ncr_tomerr(cret); } break; case NCR_ALG_DSA: @@ -151,21 +164,29 @@ int ncr_pk_pack( const struct key_item_st * key, uint8_t * packed, uint32_t * pa if (cret != CRYPT_OK) { *packed_size = max_size; err(); - return tomerr(cret); + return _ncr_tomerr(cret); + } + break; + case NCR_ALG_DH: + ret = dh_export(packed, &max_size, key->key.pk.dsa.type, (void*)&key->key.pk.dsa); + if (ret < 0) { + err(); + return ret; } break; default: err(); return -EINVAL; } - + *packed_size = max_size; + return 0; } int ncr_pk_unpack( struct key_item_st * key, const void * packed, size_t packed_size) { - int cret; + int cret, ret; if (key == NULL || packed == NULL) { err(); @@ -177,14 +198,21 @@ int ncr_pk_unpack( struct key_item_st * key, const void * packed, size_t packed_ cret = rsa_import(packed, packed_size, (void*)&key->key.pk.rsa); if (cret != CRYPT_OK) { err(); - return tomerr(cret); + return _ncr_tomerr(cret); } break; case NCR_ALG_DSA: cret = dsa_import(packed, packed_size, (void*)&key->key.pk.dsa); if (cret != CRYPT_OK) { err(); - return tomerr(cret); + return _ncr_tomerr(cret); + } + break; + case NCR_ALG_DH: + ret = dh_import(packed, packed_size, (void*)&key->key.pk.dh); + if (ret < 0) { + err(); + return ret; } break; default: @@ -208,7 +236,8 @@ struct keygen_st { static void keygen_handler(struct work_struct *instance) { unsigned long e; - int cret; + int cret, ret; + uint8_t * tmp = NULL; struct keygen_st *st = container_of(instance, struct keygen_st, pk_gen); @@ -221,7 +250,7 @@ static void keygen_handler(struct work_struct *instance) cret = rsa_make_key(st->params->params.rsa.bits/8, e, &st->private->key.pk.rsa); if (cret != CRYPT_OK) { err(); - st->ret = tomerr(cret); + st->ret = _ncr_tomerr(cret); } else st->ret = 0; break; @@ -235,15 +264,62 @@ static void keygen_handler(struct work_struct *instance) st->params->params.dsa.p_bits/8, &st->private->key.pk.dsa); if (cret != CRYPT_OK) { err(); - st->ret = tomerr(cret); + st->ret = _ncr_tomerr(cret); } else st->ret = 0; break; + case NCR_ALG_DH: { + uint8_t * p, *g; + size_t p_size, g_size; + + p_size = st->params->params.dh.p_size; + g_size = st->params->params.dh.g_size; + + tmp = kmalloc(g_size+p_size, GFP_KERNEL); + if (tmp == NULL) { + err(); + st->ret = -ENOMEM; + goto fail; + } + + p = tmp; + g = &tmp[p_size]; + + if (unlikely(copy_from_user(p, st->params->params.dh.p, p_size))) { + err(); + st->ret = -EFAULT; + goto fail; + } + + if (unlikely(copy_from_user(g, st->params->params.dh.g, g_size))) { + err(); + st->ret = -EFAULT; + goto fail; + } + + ret = dh_import_params(&st->private->key.pk.dh, p, p_size, g, g_size); + if (ret < 0) { + err(); + st->ret = ret; + goto fail; + } + + ret = dh_generate_key(&st->private->key.pk.dh); + if (ret < 0) { + st->ret = ret; + err(); + goto fail; + } + st->ret = 0; + break; + } default: err(); st->ret = -EINVAL; } +fail: + kfree(tmp); complete(&st->completed); } @@ -305,7 +381,9 @@ void ncr_pk_queue_deinit(void) destroy_workqueue(pk_wq); } -const struct algo_properties_st *ncr_key_params_get_sign_hash(const struct algo_properties_st *algo, struct ncr_key_params_st * params) +const struct algo_properties_st *ncr_key_params_get_sign_hash( + const struct algo_properties_st *algo, + struct ncr_key_params_st * params) { ncr_algorithm_t id; @@ -413,7 +491,7 @@ void * input, *output; if (cret != CRYPT_OK) { err(); - ret = tomerr(cret); + ret = _ncr_tomerr(cret); goto fail; } *osg_size = osize; @@ -475,7 +553,7 @@ void * input, *output; if (cret != CRYPT_OK) { err(); - ret = tomerr(cret); + ret = _ncr_tomerr(cret); goto fail; } @@ -540,7 +618,7 @@ void * input, *output; ctx->type, ctx->sign_hash, ctx->salt_len, &ctx->key->key.pk.rsa); if (cret != CRYPT_OK) { err(); - return tomerr(cret); + return _ncr_tomerr(cret); } *osg_size = osize; break; @@ -550,7 +628,7 @@ void * input, *output; if (cret != CRYPT_OK) { err(); - return tomerr(cret); + return _ncr_tomerr(cret); } *osg_size = osize; break; @@ -601,7 +679,7 @@ uint8_t* sig; ctx->salt_len, &stat, &ctx->key->key.pk.rsa); if (cret != CRYPT_OK) { err(); - ret = tomerr(cret); + ret = _ncr_tomerr(cret); goto fail; } @@ -616,7 +694,7 @@ uint8_t* sig; hash, hash_size, &stat, &ctx->key->key.pk.dsa); if (cret != CRYPT_OK) { err(); - ret = tomerr(cret); + ret = _ncr_tomerr(cret); goto fail; } @@ -637,3 +715,50 @@ fail: kfree(sig); return ret; } + +int ncr_pk_derive(struct key_item_st* newkey, struct key_item_st* oldkey, + struct ncr_key_derivation_params_st * params) +{ +int ret; +void* tmp = NULL; +size_t size; + + switch(params->derive) { + case NCR_DERIVE_DH: + if (oldkey->type != NCR_KEY_TYPE_PRIVATE && + oldkey->algorithm->algo != NCR_ALG_DH) { + err(); + return -EINVAL; + } + + size = params->params.params.dh.pub_size; + tmp = kmalloc(size, GFP_KERNEL); + if (tmp == NULL) { + err(); + return -ENOMEM; + } + + if (unlikely(copy_from_user(tmp, params->params.params.dh.pub, + size))) { + err(); + ret = -EFAULT; + goto fail; + } + + ret = dh_derive_gxy(newkey, &oldkey->key.pk.dh, tmp, size); + if (ret < 0) { + err(); + goto fail; + } + + break; + default: + err(); + return -EINVAL; + } + + ret = 0; +fail: + kfree(tmp); + return ret; +} diff --git a/crypto/userspace/ncr-pk.h b/crypto/userspace/ncr-pk.h index fdc5e1c005b..f234f735b45 100644 --- a/crypto/userspace/ncr-pk.h +++ b/crypto/userspace/ncr-pk.h @@ -51,4 +51,9 @@ int ncr_pk_cipher_verify(const struct ncr_pk_ctx* ctx, const struct scatterlist* sign_sg, unsigned int sign_sg_cnt, size_t sign_sg_size, const void* hash, size_t hash_size, ncr_error_t* err); +int _ncr_tomerr(int err); + +int ncr_pk_derive(struct key_item_st* newkey, struct key_item_st* oldkey, + struct ncr_key_derivation_params_st * params); + #endif diff --git a/crypto/userspace/ncr-sessions.c b/crypto/userspace/ncr-sessions.c index 466558b7095..c5b31ac8f27 100644 --- a/crypto/userspace/ncr-sessions.c +++ b/crypto/userspace/ncr-sessions.c @@ -1,22 +1,26 @@ /* * New driver for /dev/crypto device (aka CryptoDev) - * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org> + * Copyright (c) 2010 Katholieke Universiteit Leuven + * Portions Copyright (c) 2010 Phil Sutter + * + * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org> * * This file is part of linux cryptodev. * - * cryptodev 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 3 of the License, or - * (at your option) any later version. - * - * cryptodev is distributed in the hope that it will be useful, + * 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. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <linux/crypto.h> @@ -197,6 +201,8 @@ static const struct algo_properties_st algo_properties[] = { .can_encrypt=1, .can_sign=1, .key_type = NCR_KEY_TYPE_PUBLIC }, { .algo = NCR_ALG_DSA, .kstr = NULL, .is_pk = 1, .can_sign=1, .key_type = NCR_KEY_TYPE_PUBLIC }, + { .algo = NCR_ALG_DH, .kstr = NULL, .is_pk = 1, + .can_kx=1, .key_type = NCR_KEY_TYPE_PUBLIC }, { .algo = NCR_ALG_NONE } }; @@ -413,7 +419,7 @@ int ncr_session_init(struct ncr_lists* lists, void __user* arg) return ret; } -int _ncr_session_encrypt(struct session_item_st* sess, const struct scatterlist* input, unsigned input_cnt, +static int _ncr_session_encrypt(struct session_item_st* sess, const struct scatterlist* input, unsigned input_cnt, size_t input_size, void *output, unsigned output_cnt, size_t *output_size) { int ret; @@ -427,7 +433,7 @@ int ret; return ret; } /* FIXME: handle ciphers that do not require that */ - + *output_size = input_size; } else { /* public key */ ret = ncr_pk_cipher_encrypt(&sess->pk, input, input_cnt, input_size, output, output_cnt, output_size); @@ -441,7 +447,7 @@ int ret; return 0; } -int _ncr_session_decrypt(struct session_item_st* sess, const struct scatterlist* input, +static int _ncr_session_decrypt(struct session_item_st* sess, const struct scatterlist* input, unsigned input_cnt, size_t input_size, struct scatterlist *output, unsigned output_cnt, size_t *output_size) { @@ -456,7 +462,7 @@ int ret; return ret; } /* FIXME: handle ciphers that do not require equality */ - + *output_size = input_size; } else { /* public key */ ret = ncr_pk_cipher_decrypt(&sess->pk, input, input_cnt, input_size, output, output_cnt, output_size); @@ -470,7 +476,7 @@ int ret; return 0; } -void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc) +static void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc) { struct session_item_st * item, *tmp; @@ -489,6 +495,36 @@ void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc) return; } +static int _ncr_session_grow_pages(struct session_item_st *ses, int pagecount) +{ + struct scatterlist *sg; + struct page **pages; + int array_size; + + if (likely(pagecount < ses->array_size)) + return 0; + + for (array_size = ses->array_size; array_size < pagecount; + array_size *= 2) + ; + + dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n", + __func__, array_size); + pages = krealloc(ses->pages, array_size * sizeof(struct page *), + GFP_KERNEL); + if (unlikely(pages == NULL)) + return -ENOMEM; + ses->pages = pages; + sg = krealloc(ses->sg, array_size * sizeof(struct scatterlist), + GFP_KERNEL); + if (unlikely(sg == NULL)) + return -ENOMEM; + ses->sg = sg; + + ses->array_size = array_size; + return 0; +} + /* Only the output buffer is given as scatterlist */ static int get_userbuf1(struct session_item_st* ses, void __user * udata, size_t udata_size, struct scatterlist **dst_sg, unsigned *dst_cnt) @@ -500,28 +536,8 @@ static int get_userbuf1(struct session_item_st* ses, return -EINVAL; } - if (unlikely(ses->sg == NULL || ses->pages == NULL)) { - err(); - return -ENOMEM; - } - pagecount = PAGECOUNT(udata, udata_size); - - if (pagecount > ses->array_size) { - while (ses->array_size < pagecount) - ses->array_size *= 2; - - dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n", - __func__, ses->array_size); - ses->pages = krealloc(ses->pages, ses->array_size * - sizeof(struct page *), GFP_KERNEL); - ses->sg = krealloc(ses->sg, ses->array_size * - sizeof(struct scatterlist), GFP_KERNEL); - - if (unlikely(ses->sg == NULL || ses->pages == NULL)) { - return -ENOMEM; - } - } + _ncr_session_grow_pages(ses, pagecount); if (__get_userbuf(udata, udata_size, 1, pagecount, ses->pages, ses->sg)) { @@ -549,11 +565,6 @@ static int get_userbuf2(struct session_item_st* ses, return -EINVAL; } - if (unlikely(ses->sg == NULL || ses->pages == NULL)) { - err(); - return -ENOMEM; - } - src_pagecount = PAGECOUNT(op->data.udata.input, input_size); if (op->data.udata.input != op->data.udata.output) { /* non-in-situ transformation */ @@ -570,22 +581,7 @@ static int get_userbuf2(struct session_item_st* ses, } pagecount = src_pagecount + dst_pagecount; - - if (pagecount > ses->array_size) { - while (ses->array_size < pagecount) - ses->array_size *= 2; - - dprintk(2, KERN_DEBUG, "%s: reallocating to %d elements\n", - __func__, ses->array_size); - ses->pages = krealloc(ses->pages, ses->array_size * - sizeof(struct page *), GFP_KERNEL); - ses->sg = krealloc(ses->sg, ses->array_size * - sizeof(struct scatterlist), GFP_KERNEL); - - if (ses->sg == NULL || ses->pages == NULL) { - return -ENOMEM; - } - } + _ncr_session_grow_pages(ses, pagecount); if (__get_userbuf(op->data.udata.input, input_size, write_src, src_pagecount, ses->pages, ses->sg)) { @@ -622,7 +618,7 @@ static int get_userbuf2(struct session_item_st* ses, } /* Called when userspace buffers are used */ -int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st* op) +static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st* op) { int ret; struct session_item_st* sess; @@ -659,6 +655,12 @@ int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st* op) goto fail; } + if (osg_size < isg_size) { + err(); + ret = -EINVAL; + goto fail; + } + ret = _ncr_session_encrypt(sess, isg, isg_cnt, isg_size, osg, osg_cnt, &osg_size); if (ret < 0) { @@ -731,7 +733,7 @@ static int try_session_update(struct ncr_lists* lists, struct ncr_session_op_st* return 0; } -int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* op) +static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* op) { int ret; struct session_item_st* sess; diff --git a/crypto/userspace/ncr.c b/crypto/userspace/ncr.c index 1d91456af5c..87bd05204a9 100644 --- a/crypto/userspace/ncr.c +++ b/crypto/userspace/ncr.c @@ -1,22 +1,25 @@ /* * New driver for /dev/crypto device (aka CryptoDev) - - * Copyright (c) 2010 Nikos Mavrogiannopoulos <nmav@gnutls.org> * - * This file is part of linux cryptodev. + * Copyright (c) 2010 Katholieke Universiteit Leuven * - * cryptodev 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 3 of the License, or - * (at your option) any later version. + * Author: Nikos Mavrogiannopoulos <nmav@gnutls.org> * - * cryptodev is distributed in the hope that it will be useful, + * This file is part of linux cryptodev. + * + * 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. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include <linux/crypto.h> @@ -103,7 +106,7 @@ struct ncr_master_key_st st; dprintk(0, KERN_DEBUG, "Master key was previously initialized.\n"); } - dprintk(0, KERN_INFO, "Intializing master key.\n"); + dprintk(0, KERN_INFO, "Initializing master key.\n"); master_key.type = NCR_KEY_TYPE_SECRET; @@ -156,10 +159,8 @@ ncr_ioctl(struct ncr_lists* lst, struct file *filp, return ncr_master_key_set(arg); case NCRIO_KEY_GENERATE_PAIR: return ncr_key_generate_pair(&lst->key, arg); -#if 0 case NCRIO_KEY_DERIVE: return ncr_key_derive(&lst->key, arg); -#endif default: return -EINVAL; } |