summaryrefslogtreecommitdiffstats
path: root/ncr-sessions.c
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2010-07-25 22:17:22 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2010-07-25 22:17:22 +0200
commit6a2560330da7bc05ccb9bc75e70ce745acba7d6c (patch)
tree2973ea99e08e08ff9119768ca40be21cfbbcd937 /ncr-sessions.c
parentc2dda95767e03af277f4d7dab1334aa10e3ee10f (diff)
downloadcryptodev-linux-6a2560330da7bc05ccb9bc75e70ce745acba7d6c.tar.gz
cryptodev-linux-6a2560330da7bc05ccb9bc75e70ce745acba7d6c.tar.xz
cryptodev-linux-6a2560330da7bc05ccb9bc75e70ce745acba7d6c.zip
No need for ncr-direct. All session operations are being done on keys or on userspace data.
Diffstat (limited to 'ncr-sessions.c')
-rw-r--r--ncr-sessions.c412
1 files changed, 318 insertions, 94 deletions
diff --git a/ncr-sessions.c b/ncr-sessions.c
index 3202e69..f0aebc5 100644
--- a/ncr-sessions.c
+++ b/ncr-sessions.c
@@ -27,6 +27,8 @@
#include <linux/scatterlist.h>
#include <ncr-sessions.h>
+static int _ncr_session_direct_update_key(struct ncr_lists* lists, struct ncr_session_op_st* op);
+
void ncr_sessions_list_deinit(struct list_sem_st* lst)
{
if(lst) {
@@ -468,15 +470,147 @@ int ret;
return 0;
}
-/* Main update function
- */
-static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st* op)
+void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc)
+{
+ struct session_item_st * item, *tmp;
+
+ down(&lst->sem);
+
+ list_for_each_entry_safe(item, tmp, &lst->list, list) {
+ if(item->desc == desc) {
+ list_del(&item->list);
+ _ncr_sessions_item_put( item); /* decrement ref count */
+ break;
+ }
+ }
+
+ up(&lst->sem);
+
+ return;
+}
+
+/* Only the output buffer is given as scatterlist */
+static int get_userbuf1(struct session_item_st* ses,
+ struct ncr_session_op_st* op, struct scatterlist **dst_sg, unsigned *dst_cnt)
+{
+ int pagecount = 0;
+
+ if (op->data.udata.output == NULL) {
+ return -EINVAL;
+ }
+
+ pagecount = PAGECOUNT(op->data.udata.output, op->data.udata.output_size);
+
+
+ ses->available_pages = 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;
+ }
+ }
+
+ if (__get_userbuf(op->data.udata.output, op->data.udata.output_size, 1,
+ pagecount, ses->pages, ses->sg)) {
+ dprintk(1, KERN_ERR, "failed to get user pages for data input\n");
+ return -EINVAL;
+ }
+ (*dst_sg) = ses->sg;
+ *dst_cnt = pagecount;
+
+ return 0;
+}
+
+/* make op->data.udata.input and op->data.udata.output available in scatterlists */
+static int get_userbuf2(struct session_item_st* ses,
+ struct ncr_session_op_st* op, struct scatterlist **src_sg,
+ unsigned *src_cnt, struct scatterlist **dst_sg, unsigned *dst_cnt)
+{
+ int src_pagecount, dst_pagecount = 0, pagecount, write_src = 1;
+
+ if (op->data.udata.input == NULL) {
+ return -EINVAL;
+ }
+
+ src_pagecount = PAGECOUNT(op->data.udata.input, op->data.udata.input_size);
+
+ if (op->data.udata.input != op->data.udata.output) { /* non-in-situ transformation */
+ if (op->data.udata.output != NULL) {
+ dst_pagecount = PAGECOUNT(op->data.udata.output, op->data.udata.output_size);
+ write_src = 0;
+ } else {
+ dst_pagecount = 0;
+ }
+ }
+
+ ses->available_pages = 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;
+ }
+ }
+
+ if (__get_userbuf(op->data.udata.input, op->data.udata.input_size, write_src,
+ src_pagecount, ses->pages, ses->sg)) {
+ dprintk(1, KERN_ERR, "failed to get user pages for data input\n");
+ return -EINVAL;
+ }
+ (*src_sg) = ses->sg;
+ *src_cnt = src_pagecount;
+
+ if (dst_pagecount) {
+ *dst_cnt = dst_pagecount;
+ (*dst_sg) = ses->sg + src_pagecount;
+
+ if (__get_userbuf(op->data.udata.output, op->data.udata.output_size, 1, dst_pagecount,
+ ses->pages + src_pagecount, *dst_sg)) {
+ dprintk(1, KERN_ERR, "failed to get user pages for data output\n");
+ release_user_pages(ses->pages, src_pagecount);
+ return -EINVAL;
+ }
+ } else {
+ if (op->data.udata.output != NULL) {
+ *dst_cnt = src_pagecount;
+ (*dst_sg) = (*src_sg);
+ } else {
+ *dst_cnt = 0;
+ *dst_sg = NULL;
+ }
+ }
+
+ return 0;
+}
+
+/* Called when userspace buffers are used */
+int _ncr_session_direct_update(struct ncr_lists* lists, struct ncr_session_op_st* op)
{
int ret;
struct session_item_st* sess;
- struct data_item_st* data = NULL;
- struct data_item_st* odata = NULL;
- size_t new_size;
+ struct scatterlist *isg;
+ struct scatterlist *osg;
+ unsigned osg_cnt=0, isg_cnt=0;
+ size_t isg_size, osg_size;
sess = ncr_sessions_item_get( &lists->sessions, op->ses);
if (sess == NULL) {
@@ -484,65 +618,63 @@ static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st
return -EINVAL;
}
- /* obtain data item */
- data = ncr_data_item_get( &lists->data, op->data.ndata.input);
- if (data == NULL) {
+ if (down_interruptible(&sess->mem_mutex)) {
+ err();
+ _ncr_sessions_item_put(sess);
+ return -ERESTARTSYS;
+ }
+
+ ret = get_userbuf2(sess, op, &isg, &isg_cnt, &osg, &osg_cnt);
+ if (ret < 0) {
err();
- ret = -EINVAL;
goto fail;
}
+ isg_size = op->data.udata.input_size;
+ osg_size = op->data.udata.output_size;
switch(sess->op) {
case NCR_OP_ENCRYPT:
- odata = ncr_data_item_get( &lists->data, op->data.ndata.output);
- if (odata == NULL) {
- err();
- ret = -EINVAL;
- goto fail;
- }
-
- if (odata->max_data_size < data->data_size) {
+ if (osg == NULL) {
err();
ret = -EINVAL;
goto fail;
}
- odata->data_size = odata->max_data_size;
- ret = _ncr_session_encrypt(sess, &data->sg, 1, data->data_size,
- &odata->sg, 1, &odata->data_size);
+ ret = _ncr_session_encrypt(sess, isg, isg_cnt, isg_size,
+ osg, osg_cnt, &osg_size);
if (ret < 0) {
err();
goto fail;
}
+ op->data.udata.output_size = osg_size;
+
break;
case NCR_OP_DECRYPT:
- odata = ncr_data_item_get( &lists->data, op->data.ndata.output);
- if (odata == NULL) {
+ if (osg == NULL) {
err();
ret = -EINVAL;
goto fail;
}
- if (odata->max_data_size < data->data_size) {
+ if (osg_size < isg_size) {
err();
ret = -EINVAL;
goto fail;
}
- new_size = odata->max_data_size;
- ret = _ncr_session_decrypt(sess, &data->sg, 1, data->data_size,
- &odata->sg, 1, &new_size);
+ ret = _ncr_session_decrypt(sess, isg, isg_cnt, isg_size,
+ osg, osg_cnt, &osg_size);
if (ret < 0) {
err();
goto fail;
}
- odata->data_size = new_size;
+ op->data.udata.output_size = osg_size;
break;
case NCR_OP_SIGN:
case NCR_OP_VERIFY:
- ret = cryptodev_hash_update(&sess->hash, &data->sg, data->data_size);
+ ret = cryptodev_hash_update(&sess->hash, isg, isg_size);
if (ret < 0) {
err();
goto fail;
@@ -557,48 +689,41 @@ static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st
ret = 0;
fail:
- if (odata) _ncr_data_item_put(odata);
- if (data) _ncr_data_item_put(data);
+ if (sess->available_pages) {
+ release_user_pages(sess->pages, sess->available_pages);
+ sess->available_pages = 0;
+ }
+ up(&sess->mem_mutex);
_ncr_sessions_item_put(sess);
return ret;
}
-void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc)
-{
- struct session_item_st * item, *tmp;
-
- down(&lst->sem);
-
- list_for_each_entry_safe(item, tmp, &lst->list, list) {
- if(item->desc == desc) {
- list_del(&item->list);
- _ncr_sessions_item_put( item); /* decrement ref count */
- break;
- }
- }
-
- up(&lst->sem);
-
- return;
-}
-
-static int try_session_update(struct ncr_lists* lists, struct ncr_session_op_st* op)
+static int try_session_direct_update(struct ncr_lists* lists, struct ncr_session_op_st* op)
{
- if (op->data.ndata.input != NCR_DATA_INVALID) {
- return _ncr_session_update(lists, op);
+ if (op->type == NCR_KEY_DATA) {
+ if (op->data.kdata.input != NCR_KEY_INVALID)
+ return _ncr_session_direct_update_key(lists, op);
+ } else if (op->type == NCR_DIRECT_DATA) {
+ if (op->data.udata.input != NULL)
+ return _ncr_session_direct_update(lists, op);
}
return 0;
}
-static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* op)
+int _ncr_session_direct_final(struct ncr_lists* lists, struct ncr_session_op_st* op)
{
int ret;
struct session_item_st* sess;
struct data_item_st* odata = NULL;
int digest_size;
uint8_t digest[NCR_HASH_MAX_OUTPUT_SIZE];
+ uint8_t vdigest[NCR_HASH_MAX_OUTPUT_SIZE];
+ struct scatterlist *osg;
+ unsigned osg_cnt=0;
+ size_t osg_size = 0;
+ size_t orig_osg_size;
sess = ncr_sessions_item_get( &lists->sessions, op->ses);
if (sess == NULL) {
@@ -606,18 +731,31 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st*
return -EINVAL;
}
- ret = try_session_update(lists, op);
+ ret = try_session_direct_update(lists, op);
if (ret < 0) {
err();
- goto fail;
+ _ncr_sessions_item_put(sess);
+ return ret;
+ }
+
+ if (down_interruptible(&sess->mem_mutex)) {
+ err();
+ _ncr_sessions_item_put(sess);
+ return -ERESTARTSYS;
}
switch(sess->op) {
case NCR_OP_ENCRYPT:
case NCR_OP_DECRYPT:
break;
-
case NCR_OP_VERIFY:
+ ret = get_userbuf1(sess, op, &osg, &osg_cnt);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ orig_osg_size = osg_size = op->data.udata.output_size;
+
digest_size = sess->hash.digestsize;
if (digest_size == 0 || sizeof(digest) < digest_size) {
err();
@@ -630,16 +768,16 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st*
goto fail;
}
- odata = ncr_data_item_get( &lists->data, op->data.ndata.output);
- if (odata == NULL) {
- err();
- ret = -EINVAL;
- goto fail;
- }
-
if (sess->algorithm->is_hmac) {
+ ret = sg_copy_to_buffer(osg, osg_cnt, vdigest, digest_size);
+ if (ret != digest_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
if (digest_size != odata->data_size ||
- memcmp(odata->data, digest, digest_size) != 0) {
+ memcmp(vdigest, digest, digest_size) != 0) {
op->err = NCR_VERIFICATION_FAILED;
} else {
@@ -647,7 +785,7 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st*
}
} else {
/* PK signature */
- ret = ncr_pk_cipher_verify(&sess->pk, &odata->sg, 1, odata->data_size,
+ ret = ncr_pk_cipher_verify(&sess->pk, osg, osg_cnt, osg_size,
digest, digest_size, &op->err);
if (ret < 0) {
err();
@@ -657,34 +795,46 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st*
break;
case NCR_OP_SIGN:
- odata = ncr_data_item_get( &lists->data, op->data.ndata.output);
- if (odata == NULL) {
+ ret = get_userbuf1(sess, op, &osg, &osg_cnt);
+ if (ret < 0) {
err();
- ret = -EINVAL;
goto fail;
}
+ orig_osg_size = osg_size = op->data.udata.output_size;
digest_size = sess->hash.digestsize;
- if (digest_size == 0 || odata->max_data_size < digest_size) {
+ if (digest_size == 0 || osg_size < digest_size) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = cryptodev_hash_final(&sess->hash, digest);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ ret = sg_copy_from_buffer(osg, osg_cnt, digest, digest_size);
+ if (ret != digest_size) {
err();
ret = -EINVAL;
goto fail;
}
- ret = cryptodev_hash_final(&sess->hash, odata->data);
- odata->data_size = digest_size;
+ osg_size = digest_size;
cryptodev_hash_deinit(&sess->hash);
if (sess->algorithm->is_pk) {
/* PK signature */
- size_t new_size = odata->max_data_size;
- ret = ncr_pk_cipher_sign(&sess->pk, &odata->sg, 1, odata->data_size,
- &odata->sg, 1, &new_size);
+
+ ret = ncr_pk_cipher_sign(&sess->pk, osg, osg_cnt, osg_size,
+ osg, osg_cnt, &orig_osg_size);
if (ret < 0) {
err();
goto fail;
}
- odata->data_size = new_size;
+ osg_size = orig_osg_size;
}
break;
default:
@@ -693,10 +843,18 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st*
goto fail;
}
+ if (osg_size > 0)
+ op->data.udata.output_size = osg_size;
+
ret = 0;
fail:
- if (odata) _ncr_data_item_put(odata);
+ if (sess->available_pages) {
+ release_user_pages(sess->pages, sess->available_pages);
+ sess->available_pages = 0;
+ }
+ up(&sess->mem_mutex);
+
cryptodev_hash_deinit(&sess->hash);
if (sess->algorithm->is_symmetric) {
cryptodev_cipher_deinit(&sess->cipher);
@@ -710,6 +868,85 @@ fail:
return ret;
}
+/* Direct with key: Allows to hash a key */
+/* Called when userspace buffers are used */
+static int _ncr_session_direct_update_key(struct ncr_lists* lists, struct ncr_session_op_st* op)
+{
+ int ret;
+ struct session_item_st* sess;
+ struct key_item_st* key = NULL;
+ struct scatterlist *osg;
+ unsigned osg_cnt=0;
+ size_t osg_size;
+
+ sess = ncr_sessions_item_get( &lists->sessions, op->ses);
+ if (sess == NULL) {
+ err();
+ return -EINVAL;
+ }
+
+ /* read key */
+ ret = ncr_key_item_get_read( &key, &lists->key, op->data.kdata.input);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ if (key->type != NCR_KEY_TYPE_SECRET) {
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (down_interruptible(&sess->mem_mutex)) {
+ err();
+ _ncr_sessions_item_put(sess);
+ return -ERESTARTSYS;
+ }
+
+ ret = get_userbuf1(sess, op, &osg, &osg_cnt);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+
+ osg_size = op->data.kdata.output_size;
+
+ switch(sess->op) {
+ case NCR_OP_ENCRYPT:
+ case NCR_OP_DECRYPT:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ case NCR_OP_SIGN:
+ case NCR_OP_VERIFY:
+ ret = _cryptodev_hash_update(&sess->hash,
+ key->key.secret.data, key->key.secret.size);
+ if (ret < 0) {
+ err();
+ goto fail;
+ }
+ break;
+ default:
+ err();
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ ret = 0;
+
+fail:
+ if (sess->available_pages) {
+ release_user_pages(sess->pages, sess->available_pages);
+ sess->available_pages = 0;
+ }
+ up(&sess->mem_mutex);
+ if (key) _ncr_key_item_put(key);
+ _ncr_sessions_item_put(sess);
+
+ return ret;
+}
+
int ncr_session_update(struct ncr_lists* lists, void __user* arg)
{
struct ncr_session_op_st op;
@@ -722,8 +959,8 @@ int ncr_session_update(struct ncr_lists* lists, void __user* arg)
if (op.type == NCR_DIRECT_DATA)
ret = _ncr_session_direct_update(lists, &op);
- else if (op.type == NCR_DATA)
- ret = _ncr_session_update(lists, &op);
+ else if (op.type == NCR_KEY_DATA)
+ ret = _ncr_session_direct_update_key(lists, &op);
else
ret = -EINVAL;
@@ -750,14 +987,7 @@ int ncr_session_final(struct ncr_lists* lists, void __user* arg)
return -EFAULT;
}
- if (op.type == NCR_DATA) {
- ret = _ncr_session_final(lists, &op);
- } else if (op.type == NCR_DIRECT_DATA) {
- ret = _ncr_session_direct_final(lists, &op);
- } else {
- ret = -EINVAL;
- }
-
+ ret = _ncr_session_direct_final(lists, &op);
if (unlikely(ret)) {
err();
return ret;
@@ -787,13 +1017,7 @@ int ncr_session_once(struct ncr_lists* lists, void __user* arg)
}
kop.op.ses = kop.init.ses;
- if (kop.op.type == NCR_DIRECT_DATA)
- ret = _ncr_session_direct_final(lists, &kop.op);
- else if (kop.op.type == NCR_DATA)
- ret = _ncr_session_final(lists, &kop.op);
- else
- ret = -EINVAL;
-
+ ret = _ncr_session_direct_final(lists, &kop.op);
if (ret < 0) {
err();
return ret;