diff options
Diffstat (limited to 'ncr-key.c')
-rw-r--r-- | ncr-key.c | 390 |
1 files changed, 266 insertions, 124 deletions
diff --git a/ncr-key.c b/ncr-key.c index bf438fa22cc..406e03299c3 100644 --- a/ncr-key.c +++ b/ncr-key.c @@ -27,12 +27,11 @@ #include <linux/slab.h> #include <linux/random.h> #include <linux/uaccess.h> -#include "cryptodev.h" #include <linux/scatterlist.h> +#include <net/netlink.h> #include "ncr.h" #include "ncr-int.h" - -static void ncr_key_clear(struct key_item_st* item); +#include "utils.h" static int key_list_deinit_fn(int id, void *item, void *unused) { @@ -151,7 +150,7 @@ static void _ncr_key_remove(struct ncr_lists *lst, ncr_key_t desc) _ncr_key_item_put(item); } -int ncr_key_init(struct ncr_lists *lst, void __user* arg) +int ncr_key_init(struct ncr_lists *lst) { ncr_key_t desc; struct key_item_st* key; @@ -190,49 +189,33 @@ int ncr_key_init(struct ncr_lists *lst, void __user* arg) desc = key->desc; mutex_unlock(&lst->key_idr_mutex); - ret = copy_to_user(arg, &desc, sizeof(desc)); - if (unlikely(ret)) { - _ncr_key_remove(lst, desc); - return -EFAULT; - } - return ret; + return desc; err_limits: ncr_limits_remove(current_euid(), task_pid_nr(current), LIMIT_TYPE_KEY); return ret; } -int ncr_key_deinit(struct ncr_lists *lst, void __user* arg) +int ncr_key_deinit(struct ncr_lists *lst, ncr_key_t desc) { - ncr_key_t desc; - - if (unlikely(copy_from_user(&desc, arg, sizeof(desc)))) { - err(); - return -EFAULT; - } - _ncr_key_remove(lst, desc); - return 0; } -/* "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_export(struct ncr_lists *lst, void __user* arg) +int ncr_key_export(struct ncr_lists *lst, const struct ncr_key_export *data, + struct nlattr *tb[]) { -struct ncr_key_data_st data; struct key_item_st* item = NULL; void* tmp = NULL; uint32_t tmp_size; int ret; - if (unlikely(copy_from_user(&data, arg, sizeof(data)))) { + if (data->buffer_size < 0) { err(); - return -EFAULT; + return -EINVAL; } - ret = ncr_key_item_get_read( &item, lst, data.key); + ret = ncr_key_item_get_read(&item, lst, data->key); if (ret < 0) { err(); return ret; @@ -246,15 +229,15 @@ int ret; switch (item->type) { case NCR_KEY_TYPE_SECRET: - if (item->key.secret.size > data.idata_size) { + if (item->key.secret.size > data->buffer_size) { err(); - ret = -EINVAL; + ret = -ERANGE; goto fail; } /* found */ if (item->key.secret.size > 0) { - ret = copy_to_user(data.idata, item->key.secret.data, item->key.secret.size); + ret = copy_to_user(data->buffer, item->key.secret.data, item->key.secret.size); if (unlikely(ret)) { err(); ret = -EFAULT; @@ -262,11 +245,11 @@ int ret; } } - data.idata_size = item->key.secret.size; + ret = item->key.secret.size; break; case NCR_KEY_TYPE_PUBLIC: case NCR_KEY_TYPE_PRIVATE: - tmp_size = data.idata_size; + tmp_size = data->buffer_size; tmp = kmalloc(tmp_size, GFP_KERNEL); if (tmp == NULL) { @@ -276,20 +259,19 @@ int ret; } ret = ncr_pk_pack(item, tmp, &tmp_size); - data.idata_size = tmp_size; - if (ret < 0) { err(); goto fail; } - ret = copy_to_user(data.idata, tmp, tmp_size); + ret = copy_to_user(data->buffer, tmp, tmp_size); if (unlikely(ret)) { err(); ret = -EFAULT; goto fail; } + ret = tmp_size; break; default: err(); @@ -297,12 +279,6 @@ int ret; goto fail; } - if (unlikely(copy_to_user(arg, &data, sizeof(data)))) { - err(); - ret = -EFAULT; - } else - ret = 0; - fail: kfree(tmp); if (item) @@ -311,23 +287,30 @@ fail: } -/* "imports" a key from a data item. If the key is not exportable - * to userspace then the key item will also not be. - */ -int ncr_key_import(struct ncr_lists *lst, void __user* arg) +int ncr_key_update_flags(struct key_item_st* item, const struct nlattr *nla) +{ + uint32_t flags; + + if (nla == NULL) + return 0; + flags = nla_get_u32(nla); + if (!capable(CAP_SYS_ADMIN) + && (flags & (NCR_KEY_FLAG_WRAPPING | NCR_KEY_FLAG_UNWRAPPING)) != 0) + return -EPERM; + item->flags = flags; + return 0; +} + +int ncr_key_import(struct ncr_lists *lst, const struct ncr_key_import *data, + struct nlattr *tb[]) { -struct ncr_key_data_st data; +const struct nlattr *nla; struct key_item_st* item = NULL; int ret; void* tmp = NULL; size_t tmp_size; - if (unlikely(copy_from_user(&data, arg, sizeof(data)))) { - err(); - return -EFAULT; - } - - ret = ncr_key_item_get_write( &item, lst, data.key); + ret = ncr_key_item_get_write( &item, lst, data->key); if (ret < 0) { err(); return ret; @@ -335,42 +318,55 @@ size_t tmp_size; ncr_key_clear(item); - tmp = kmalloc(data.idata_size, GFP_KERNEL); + tmp = kmalloc(data->data_size, GFP_KERNEL); if (tmp == NULL) { err(); ret = -ENOMEM; goto fail; } - if (unlikely(copy_from_user(tmp, data.idata, data.idata_size))) { + if (unlikely(copy_from_user(tmp, data->data, data->data_size))) { err(); ret = -EFAULT; goto fail; } - tmp_size = data.idata_size; - - item->type = data.type; - item->algorithm = _ncr_algo_to_properties(data.algorithm); - if (item->algorithm == NULL) { + tmp_size = data->data_size; + + nla = tb[NCR_ATTR_KEY_TYPE]; + if (tb == NULL) { err(); ret = -EINVAL; goto fail; } - item->flags = data.flags; + item->type = nla_get_u32(nla); - if (data.key_id_size > MAX_KEY_ID_SIZE) { + item->algorithm = _ncr_nla_to_properties(tb[NCR_ATTR_ALGORITHM]); + if (item->algorithm == NULL) { err(); ret = -EINVAL; goto fail; } - item->key_id_size = data.key_id_size; - if (data.key_id_size > 0) - memcpy(item->key_id, data.key_id, data.key_id_size); + ret = ncr_key_update_flags(item, tb[NCR_ATTR_KEY_FLAGS]); + if (ret < 0) { + err(); + goto fail; + } + + nla = tb[NCR_ATTR_KEY_ID]; + if (nla != NULL) { + if (nla_len(nla) > MAX_KEY_ID_SIZE) { + err(); + ret = -EOVERFLOW; + goto fail; + } + + item->key_id_size = nla_len(nla); + memcpy(item->key_id, nla_data(nla), item->key_id_size); + } switch(item->type) { case NCR_KEY_TYPE_SECRET: - if (tmp_size > NCR_CIPHER_MAX_KEY_LEN) { err(); ret = -EINVAL; @@ -405,7 +401,7 @@ fail: return ret; } -static void ncr_key_clear(struct key_item_st* item) +void ncr_key_clear(struct key_item_st* item) { /* clears any previously allocated parameters */ if (item->type == NCR_KEY_TYPE_PRIVATE || @@ -423,20 +419,16 @@ static void ncr_key_clear(struct key_item_st* item) /* Generate a secret key */ -int ncr_key_generate(struct ncr_lists *lst, void __user* arg) +int ncr_key_generate(struct ncr_lists *lst, const struct ncr_key_generate *gen, + struct nlattr *tb[]) { -struct ncr_key_generate_st gen; +const struct nlattr *nla; struct key_item_st* item = NULL; const struct algo_properties_st *algo; int ret; size_t size; - if (unlikely(copy_from_user(&gen, arg, sizeof(gen)))) { - err(); - return -EFAULT; - } - - ret = ncr_key_item_get_write( &item, lst, gen.desc); + ret = ncr_key_item_get_write(&item, lst, gen->key); if (ret < 0) { err(); return ret; @@ -445,8 +437,13 @@ size_t size; ncr_key_clear(item); /* we generate only secret keys */ - item->flags = gen.params.keyflags; - algo = _ncr_algo_to_properties(gen.params.algorithm); + ret = ncr_key_update_flags(item, tb[NCR_ATTR_KEY_FLAGS]); + if (ret < 0) { + err(); + goto fail; + } + + algo = _ncr_nla_to_properties(tb[NCR_ATTR_ALGORITHM]); if (algo == NULL) { err(); ret = -EINVAL; @@ -454,11 +451,19 @@ size_t size; } item->type = algo->key_type; if (item->type == NCR_KEY_TYPE_SECRET) { + u32 key_bits; + item->algorithm = algo; - size = gen.params.params.secret.bits/8; - if ((gen.params.params.secret.bits % 8 != 0) || - (size > NCR_CIPHER_MAX_KEY_LEN)) { + nla = tb[NCR_ATTR_SECRET_KEY_BITS]; + if (nla == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + key_bits = nla_get_u32(nla); + size = key_bits / 8; + if (key_bits % 8 != 0 || size > NCR_CIPHER_MAX_KEY_LEN) { err(); ret = -EINVAL; goto fail; @@ -486,18 +491,120 @@ fail: return ret; } -int ncr_key_info(struct ncr_lists *lst, void __user* arg) +/* Those values are derived from "ECRYPT II Yearly Report on Algorithms and + * Keysizes (2009-2010)". It maps the strength of public key algorithms to + * symmetric ones. Should be kept up to date. + */ +static const struct { + unsigned int bits; /* sec level */ + unsigned int rsa_bits; + unsigned int dlog_bits; +} ecrypt_vals[] = { + {64, 816, 816}, + {80, 1248, 1248}, + {112, 2432, 2432}, + {128, 3248, 3248}, + {160, 5312, 5312}, + {192, 7936, 7936}, + {256, 15424, 15424}, + {0,0,0} +}; + +static unsigned int rsa_to_bits(unsigned int rsa_bits) { -struct ncr_key_info_st info; -struct key_item_st* item = NULL; -int ret; +int i = 1; - if (unlikely(copy_from_user(&info, arg, sizeof(info)))) { - err(); - return -EFAULT; + if (rsa_bits <= ecrypt_vals[0].rsa_bits) + return ecrypt_vals[0].rsa_bits; + + do { + if (rsa_bits <= ecrypt_vals[i].rsa_bits && + rsa_bits > ecrypt_vals[i-1].rsa_bits) { + + return ecrypt_vals[i].bits; + } + } while(ecrypt_vals[++i].bits != 0); + + /* return the highest found so far */ + return ecrypt_vals[i-1].bits; +} + +static unsigned int dlog_to_bits(unsigned int dlog_bits) +{ +int i = 1; + + if (dlog_bits <= ecrypt_vals[0].dlog_bits) + return ecrypt_vals[0].dlog_bits; + + do { + if (dlog_bits <= ecrypt_vals[i].dlog_bits && + dlog_bits > ecrypt_vals[i-1].dlog_bits) { + + return ecrypt_vals[i].bits; + } + } while(ecrypt_vals[++i].bits != 0); + + /* return the highest found so far */ + return ecrypt_vals[i-1].bits; +} + +/* returns the security level of the key in bits. Private/Public keys + * are mapped to symmetric key bits using the ECRYPT II 2010 recommendation. + */ +int _ncr_key_get_sec_level(struct key_item_st* item) +{ +int bits; + + /* FIXME: should we move everything here into algorithm properties? + */ + if (item->type == NCR_KEY_TYPE_SECRET) { + if (item->algorithm->algo == NCR_ALG_3DES_CBC) + return 112; + + return item->key.secret.size*8; + } else if (item->type == NCR_KEY_TYPE_PRIVATE) { + switch(item->algorithm->algo) { + case NCR_ALG_RSA: + bits = ncr_pk_get_rsa_size(&item->key.pk.rsa); + if (bits < 0) { + err(); + return bits; + } + + return rsa_to_bits(bits); + case NCR_ALG_DSA: + bits = ncr_pk_get_dsa_size(&item->key.pk.dsa); + if (bits < 0) { + err(); + return bits; + } + + return dlog_to_bits(bits); + case NCR_ALG_DH: + bits = ncr_pk_get_dh_size(&item->key.pk.dh); + if (bits < 0) { + err(); + return bits; + } + + return dlog_to_bits(bits); + default: + return -EINVAL; + } + } else { + return -EINVAL; } +} - ret = ncr_key_item_get_read(&item, lst, info.key); +int ncr_key_get_info(struct ncr_lists *lst, struct ncr_out *out, + const struct ncr_key_get_info *info, struct nlattr *tb[]) +{ +const struct nlattr *nla; +const u16 *attr, *attr_end; +struct key_item_st* item = NULL; +int ret; + + ret = ncr_key_item_get_read(&item, lst, info->key); if (ret < 0) { err(); return ret; @@ -509,11 +616,41 @@ int ret; goto fail; } - info.flags = item->flags; - info.type = item->type; - info.algorithm = item->algorithm->algo; - - ret = 0; + nla = tb[NCR_ATTR_WANTED_ATTRS]; + if (nla == NULL || nla_len(nla) % sizeof(u16) != 0) { + err(); + ret = -EINVAL; + goto fail; + } + attr = nla_data(nla); + attr_end = attr + nla_len(nla) / sizeof(u16); + while (attr < attr_end) { + switch (*attr) { + case NCR_ATTR_KEY_FLAGS: + ret = ncr_out_put_u32(out, *attr, item->flags); + break; + case NCR_ATTR_KEY_TYPE: + ret = ncr_out_put_u32(out, *attr, item->type); + break; + case NCR_ATTR_ALGORITHM: + ret = ncr_out_put_string(out, *attr, + item->algorithm->kstr); + break; + default: + break; /* Silently ignore */ + } + if (ret != 0) { + err(); + goto fail; + } + attr++; + } + + ret = ncr_out_finish(out); + if (ret != 0) { + err(); + goto fail; + } fail: _ncr_key_item_put( item); @@ -521,25 +658,21 @@ fail: return ret; } -int ncr_key_generate_pair(struct ncr_lists *lst, void __user* arg) +int ncr_key_generate_pair(struct ncr_lists *lst, + const struct ncr_key_generate_pair *gen, + struct nlattr *tb[]) { -struct ncr_key_generate_st gen; struct key_item_st* private = NULL; struct key_item_st* public = NULL; int ret; - if (unlikely(copy_from_user(&gen, arg, sizeof(gen)))) { - err(); - return -EFAULT; - } - - ret = ncr_key_item_get_write( &private, lst, gen.desc); + ret = ncr_key_item_get_write(&private, lst, gen->private_key); if (ret < 0) { err(); goto fail; } - ret = ncr_key_item_get_write( &public, lst, gen.desc2); + ret = ncr_key_item_get_write(&public, lst, gen->public_key); if (ret < 0) { err(); goto fail; @@ -549,8 +682,8 @@ int ret; ncr_key_clear(private); /* we generate only secret keys */ - private->flags = public->flags = gen.params.keyflags; - private->algorithm = public->algorithm = _ncr_algo_to_properties(gen.params.algorithm); + private->algorithm = public->algorithm + = _ncr_nla_to_properties(tb[NCR_ATTR_ALGORITHM]); if (private->algorithm == NULL) { err(); ret = -EINVAL; @@ -558,10 +691,21 @@ int ret; } public->type = public->algorithm->key_type; private->type = NCR_KEY_TYPE_PRIVATE; + ret = ncr_key_update_flags(private, tb[NCR_ATTR_KEY_FLAGS]); + if (ret < 0) { + err(); + goto fail; + } + ret = ncr_key_update_flags(public, tb[NCR_ATTR_KEY_FLAGS]); + if (ret < 0) { + err(); + goto fail; + } + public->flags |= (NCR_KEY_FLAG_EXPORTABLE|NCR_KEY_FLAG_WRAPPABLE); if (public->type == NCR_KEY_TYPE_PUBLIC) { - ret = ncr_pk_generate(public->algorithm, &gen.params, private, public); + ret = ncr_pk_generate(public->algorithm, tb, private, public); if (ret < 0) { err(); goto fail; @@ -585,28 +729,28 @@ fail: return ret; } -/* "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 ncr_lists *lst, void __user* arg) +int ncr_key_derive(struct ncr_lists *lst, const struct ncr_key_derive *data, + struct nlattr *tb[]) { -struct ncr_key_derivation_params_st data; int ret; struct key_item_st* key = NULL; struct key_item_st* newkey = NULL; - if (unlikely(copy_from_user(&data, arg, sizeof(data)))) { - err(); - return -EFAULT; - } - - ret = ncr_key_item_get_read( &key, lst, data.key); + ret = ncr_key_item_get_read(&key, lst, data->input_key); if (ret < 0) { err(); return ret; } + + /* wrapping keys cannot be used for anything except wrapping. + */ + if (key->flags & NCR_KEY_FLAG_WRAPPING || key->flags & NCR_KEY_FLAG_UNWRAPPING) { + err(); + ret = -EINVAL; + goto fail; + } - ret = ncr_key_item_get_write( &newkey, lst, data.newkey); + ret = ncr_key_item_get_write(&newkey, lst, data->new_key); if (ret < 0) { err(); goto fail; @@ -614,12 +758,16 @@ struct key_item_st* newkey = NULL; ncr_key_clear(newkey); - newkey->flags = data.keyflags; + ret = ncr_key_update_flags(newkey, tb[NCR_ATTR_KEY_FLAGS]); + if (ret < 0) { + err(); + goto fail; + } switch (key->type) { case NCR_KEY_TYPE_PUBLIC: case NCR_KEY_TYPE_PRIVATE: - ret = ncr_pk_derive(newkey, key, &data); + ret = ncr_pk_derive(newkey, key, tb); if (ret < 0) { err(); goto fail; @@ -631,12 +779,6 @@ struct key_item_st* newkey = NULL; 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); |