summaryrefslogtreecommitdiffstats
path: root/crypto/userspace/ncr-key.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/userspace/ncr-key.c')
-rw-r--r--crypto/userspace/ncr-key.c389
1 files changed, 266 insertions, 123 deletions
diff --git a/crypto/userspace/ncr-key.c b/crypto/userspace/ncr-key.c
index 82fa5113662..de2a4ab70f1 100644
--- a/crypto/userspace/ncr-key.c
+++ b/crypto/userspace/ncr-key.c
@@ -29,9 +29,9 @@
#include <linux/random.h>
#include <linux/uaccess.h>
#include <linux/scatterlist.h>
+#include <net/netlink.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)
{
@@ -150,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;
@@ -189,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;
@@ -245,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;
@@ -261,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) {
@@ -275,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();
@@ -296,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)
@@ -310,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;
@@ -334,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;
@@ -404,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 ||
@@ -422,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;
@@ -444,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;
@@ -453,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;
@@ -485,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;
@@ -508,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);
@@ -520,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;
@@ -548,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;
@@ -557,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;
@@ -584,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;
@@ -613,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;
@@ -630,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);