From 6a2560330da7bc05ccb9bc75e70ce745acba7d6c Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sun, 25 Jul 2010 22:17:22 +0200 Subject: No need for ncr-direct. All session operations are being done on keys or on userspace data. --- .gitignore | 1 - Makefile | 4 +- examples/Makefile | 3 - examples/ncr-direct.c | 443 -------------------------------------------------- examples/ncr.c | 116 ++++--------- examples/pk.c | 185 ++++++--------------- ncr-sessions-direct.c | 375 ------------------------------------------ ncr-sessions.c | 412 +++++++++++++++++++++++++++++++++++----------- ncr.h | 9 +- 9 files changed, 407 insertions(+), 1141 deletions(-) delete mode 100644 examples/ncr-direct.c diff --git a/.gitignore b/.gitignore index e3f0923..4379d92 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,6 @@ modules.order examples/cipher examples/hmac examples/ncr -examples/ncr-direct examples/pk examples/speed releases diff --git a/Makefile b/Makefile index 2babafd..f85e7bd 100644 --- a/Makefile +++ b/Makefile @@ -67,8 +67,8 @@ 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-data.o ncr-key.o ncr-limits.o ncr-sessions.o ncr-pk.o \ - ncr-sessions-direct.o \ + ncr-data.o ncr-key.o ncr-limits.o ncr-pk.o \ + ncr-sessions-direct.o ncr-sessions.o \ ncr-key-wrap.o ncr-key-storage.o $(TOMMATH_OBJECTS) \ $(TOMCRYPT_OBJECTS) diff --git a/examples/Makefile b/examples/Makefile index f482649..ff5381d 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -17,9 +17,6 @@ hmac: hmac.c ncr: ncr.c $(CC) $(CFLAGS) $< -o $@ -ncr-direct: ncr-direct.c - $(CC) $(CFLAGS) $< -o $@ - pk: pk.c $(CC) $(CFLAGS) $< -o $@ -L/usr/local/lib -lgnutls diff --git a/examples/ncr-direct.c b/examples/ncr-direct.c deleted file mode 100644 index 0908e2c..0000000 --- a/examples/ncr-direct.c +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Demo on how to use /dev/crypto device for HMAC. - * - * Placed under public domain. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "../ncr.h" -#include - -#define DATA_SIZE 4096 -#define KEY_DATA_SIZE 16 - - -struct aes_vectors_st { - const uint8_t* key; - const uint8_t* plaintext; - const uint8_t* ciphertext; -} aes_vectors[] = { - { - .key = (uint8_t*)"\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - .plaintext = (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - .ciphertext = (uint8_t*)"\x4b\xc3\xf8\x83\x45\x0c\x11\x3c\x64\xca\x42\xe1\x11\x2a\x9e\x87", - }, - { - .key = (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - .plaintext = (uint8_t*)"\xf3\x44\x81\xec\x3c\xc6\x27\xba\xcd\x5d\xc3\xfb\x08\xf2\x73\xe6", - .ciphertext = (uint8_t*)"\x03\x36\x76\x3e\x96\x6d\x92\x59\x5a\x56\x7c\xc9\xce\x53\x7f\x5e", - }, - { - .key = (uint8_t*)"\x10\xa5\x88\x69\xd7\x4b\xe5\xa3\x74\xcf\x86\x7c\xfb\x47\x38\x59", - .plaintext = (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - .ciphertext = (uint8_t*)"\x6d\x25\x1e\x69\x44\xb0\x51\xe0\x4e\xaa\x6f\xb4\xdb\xf7\x84\x65", - }, - { - .key = (uint8_t*)"\xca\xea\x65\xcd\xbb\x75\xe9\x16\x9e\xcd\x22\xeb\xe6\xe5\x46\x75", - .plaintext = (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - .ciphertext = (uint8_t*)"\x6e\x29\x20\x11\x90\x15\x2d\xf4\xee\x05\x81\x39\xde\xf6\x10\xbb", - }, - { - .key = (uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe", - .plaintext = (uint8_t*)"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", - .ciphertext = (uint8_t*)"\x9b\xa4\xa9\x14\x3f\x4e\x5d\x40\x48\x52\x1c\x4f\x88\x77\xd8\x8e", - }, -}; - -/* AES cipher */ -static int -test_ncr_aes(int cfd) -{ - struct ncr_data_init_st dinit; - ncr_key_t key; - struct ncr_key_data_st keydata; - struct ncr_data_st kdata; - ncr_data_t dd, dd2; - uint8_t data[KEY_DATA_SIZE]; - int i, j; - struct ncr_session_once_op_st nop; - - dinit.max_object_size = KEY_DATA_SIZE; - dinit.flags = NCR_DATA_FLAG_EXPORTABLE; - dinit.initial_data = NULL; - dinit.initial_data_size = 0; - - if (ioctl(cfd, NCRIO_DATA_INIT, &dinit)) { - fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); - perror("ioctl(NCRIO_DATA_INIT)"); - return 1; - } - - dd = dinit.desc; - - if (ioctl(cfd, NCRIO_DATA_INIT, &dinit)) { - fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__); - perror("ioctl(NCRIO_DATA_INIT)"); - return 1; - } - - dd2 = dinit.desc; - - /* convert it to key */ - if (ioctl(cfd, NCRIO_KEY_INIT, &key)) { - perror("ioctl(NCRIO_KEY_INIT)"); - return 1; - } - - keydata.key_id[0] = 'a'; - keydata.key_id[2] = 'b'; - keydata.key_id_size = 2; - keydata.type = NCR_KEY_TYPE_SECRET; - keydata.algorithm = NCR_ALG_AES_CBC; - keydata.flags = NCR_KEY_FLAG_EXPORTABLE; - - - fprintf(stdout, "Tests on AES Encryption\n"); - for (i=0;i #include -/* 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 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) { - err(); - return -EINVAL; - } - - 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(); - goto fail; - } - isg_size = op->data.udata.input_size; - osg_size = op->data.udata.output_size; - - switch(sess->op) { - case NCR_OP_ENCRYPT: - if (osg == NULL) { - err(); - ret = -EINVAL; - goto fail; - } - - 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: - if (osg == NULL) { - err(); - ret = -EINVAL; - goto fail; - } - - if (osg_size < isg_size) { - err(); - ret = -EINVAL; - goto fail; - } - - ret = _ncr_session_decrypt(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_SIGN: - case NCR_OP_VERIFY: - ret = cryptodev_hash_update(&sess->hash, isg, isg_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); - _ncr_sessions_item_put(sess); - - return ret; -} - -static int try_session_direct_update(struct ncr_lists* lists, struct ncr_session_op_st* op) -{ - if (op->data.udata.input != NULL) { - return _ncr_session_direct_update(lists, op); - } - - return 0; -} - -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) { - err(); - return -EINVAL; - } - - ret = try_session_direct_update(lists, op); - if (ret < 0) { - err(); - _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(); - ret = -EINVAL; - goto fail; - } - ret = cryptodev_hash_final(&sess->hash, digest); - if (ret < 0) { - err(); - 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(vdigest, digest, digest_size) != 0) { - - op->err = NCR_VERIFICATION_FAILED; - } else { - op->err = NCR_SUCCESS; - } - } else { - /* PK signature */ - ret = ncr_pk_cipher_verify(&sess->pk, osg, osg_cnt, osg_size, - digest, digest_size, &op->err); - if (ret < 0) { - err(); - goto fail; - } - } - break; - - case NCR_OP_SIGN: - 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 || 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; - } - osg_size = digest_size; - - cryptodev_hash_deinit(&sess->hash); - - if (sess->algorithm->is_pk) { - /* PK signature */ - - ret = ncr_pk_cipher_sign(&sess->pk, osg, osg_cnt, osg_size, - osg, osg_cnt, &orig_osg_size); - if (ret < 0) { - err(); - goto fail; - } - osg_size = orig_osg_size; - } - break; - default: - err(); - ret = -EINVAL; - goto fail; - } - - if (osg_size > 0) - op->data.udata.output_size = osg_size; - - ret = 0; - -fail: - 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); - } else { - ncr_pk_cipher_deinit(&sess->pk); - } - - _ncr_sessions_item_put(sess); - _ncr_session_remove(&lists->sessions, op->ses); - - return ret; -} - 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 #include +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; diff --git a/ncr.h b/ncr.h index 37d1f5d..e992c7b 100644 --- a/ncr.h +++ b/ncr.h @@ -281,7 +281,7 @@ typedef enum { } ncr_error_t; typedef enum { - NCR_DATA, + NCR_KEY_DATA, NCR_DIRECT_DATA, } ncr_data_type_t; @@ -291,11 +291,12 @@ struct ncr_session_op_st { union { struct { - ncr_data_t input; - ncr_data_t output; /* when verifying signature this is + ncr_key_t input; + void* output; /* when verifying signature this is * the place of the signature. */ - } ndata; + size_t output_size; + } kdata; struct { void* input; size_t input_size; -- cgit