diff options
author | Miloslav Trmač <mitr@redhat.com> | 2010-07-26 21:07:19 +0200 |
---|---|---|
committer | Miloslav Trmač <mitr@redhat.com> | 2010-07-26 21:07:19 +0200 |
commit | 7cc28b8bafe112037edae18ea0e590e7c9d074fa (patch) | |
tree | 5836f1f9cdd22d731e986ea4f8ed73649bf7b6e4 /crypto/userspace/ncr-sessions.c | |
parent | da3eeeff5744e8ea4bcdb819db3afad6437f5231 (diff) | |
parent | a04fd1aa4f807e2f97632a46070306e1389264ed (diff) | |
download | kernel-crypto-7cc28b8bafe112037edae18ea0e590e7c9d074fa.tar.gz kernel-crypto-7cc28b8bafe112037edae18ea0e590e7c9d074fa.tar.xz kernel-crypto-7cc28b8bafe112037edae18ea0e590e7c9d074fa.zip |
Merge branch 'standalone-rename' into userspace-crypto
Conflicts:
crypto/userspace/Makefile
crypto/userspace/ncr-data.c
crypto/userspace/ncr-key-storage.c
crypto/userspace/ncr-key-wrap.c
crypto/userspace/ncr-key.c
crypto/userspace/ncr-limits.c
crypto/userspace/ncr-pk.c
crypto/userspace/ncr-sessions.c
crypto/userspace/ncr.c
Diffstat (limited to 'crypto/userspace/ncr-sessions.c')
-rw-r--r-- | crypto/userspace/ncr-sessions.c | 954 |
1 files changed, 566 insertions, 388 deletions
diff --git a/crypto/userspace/ncr-sessions.c b/crypto/userspace/ncr-sessions.c index 5d9fc93f3be..42a352ca62b 100644 --- a/crypto/userspace/ncr-sessions.c +++ b/crypto/userspace/ncr-sessions.c @@ -22,8 +22,11 @@ #include <linux/crypto.h> #include <linux/cryptodev.h> #include <linux/ncr.h> -#include "ncr_int.h" +#include "ncr-int.h" +#include <linux/mm_types.h> +#include <linux/scatterlist.h> +static int _ncr_session_update_key(struct ncr_lists* lists, struct ncr_session_op_st* op); static void _ncr_session_remove(struct list_sem_st* lst, ncr_session_t desc); void ncr_sessions_list_deinit(struct list_sem_st* lst) @@ -84,6 +87,8 @@ void _ncr_sessions_item_put( struct session_item_st* item) cryptodev_hash_deinit(&item->hash); if (item->key) _ncr_key_item_put(item->key); + kfree(item->sg); + kfree(item->pages); kfree(item); } } @@ -92,13 +97,25 @@ struct session_item_st* ncr_session_new(struct list_sem_st* lst) { struct session_item_st* sess; - sess = kmalloc(sizeof(*sess), GFP_KERNEL); + sess = kzalloc(sizeof(*sess), GFP_KERNEL); if (sess == NULL) { err(); return NULL; } - memset(sess, 0, sizeof(*sess)); + sess->array_size = DEFAULT_PREALLOC_PAGES; + sess->pages = kzalloc(sess->array_size * + sizeof(struct page *), GFP_KERNEL); + sess->sg = kzalloc(sess->array_size * + sizeof(struct scatterlist), GFP_KERNEL); + if (sess->sg == NULL || sess->pages == NULL) { + err(); + kfree(sess->sg); + kfree(sess->pages); + kfree(sess); + return NULL; + } + init_MUTEX(&sess->mem_mutex); atomic_set(&sess->refcnt, 1); @@ -112,186 +129,96 @@ struct session_item_st* ncr_session_new(struct list_sem_st* lst) return sess; } -static const struct algo_properties_st { - ncr_algorithm_t algo; - const char* kstr; - unsigned needs_iv:1; - unsigned hmac:1; - unsigned can_sign:1; - unsigned can_digest:1; - unsigned can_encrypt:1; - unsigned symmetric:1; - int digest_size; -} algo_properties[] = { +static const struct algo_properties_st algo_properties[] = { { .algo = NCR_ALG_NULL, .kstr = "ecb(cipher_null)", - .needs_iv = 0, .symmetric=1, .can_encrypt=1 }, + .needs_iv = 0, .is_symmetric=1, .can_encrypt=1, + .key_type = NCR_KEY_TYPE_INVALID }, { .algo = NCR_ALG_3DES_CBC, .kstr = "cbc(des3_ede)", - .needs_iv = 1, .symmetric=1, .can_encrypt=1 }, + .needs_iv = 1, .is_symmetric=1, .can_encrypt=1, + .key_type = NCR_KEY_TYPE_SECRET }, { .algo = NCR_ALG_AES_CBC, .kstr = "cbc(aes)", - .needs_iv = 1, .symmetric=1, .can_encrypt=1 }, + .needs_iv = 1, .is_symmetric=1, .can_encrypt=1, + .key_type = NCR_KEY_TYPE_SECRET }, { .algo = NCR_ALG_CAMELLIA_CBC, .kstr = "cbc(camelia)", - .needs_iv = 1, .symmetric=1, .can_encrypt=1 }, + .needs_iv = 1, .is_symmetric=1, .can_encrypt=1, + .key_type = NCR_KEY_TYPE_SECRET }, { .algo = NCR_ALG_AES_CTR, .kstr = "ctr(aes)", - .needs_iv = 1, .symmetric=1, .can_encrypt=1 }, + .needs_iv = 1, .is_symmetric=1, .can_encrypt=1, + .key_type = NCR_KEY_TYPE_SECRET }, { .algo = NCR_ALG_CAMELLIA_CTR, .kstr = "ctr(camelia)", - .needs_iv = 1, .symmetric=1, .can_encrypt=1 }, + .needs_iv = 1, .is_symmetric=1, .can_encrypt=1, + .key_type = NCR_KEY_TYPE_SECRET }, { .algo = NCR_ALG_ARCFOUR, .kstr = NULL, - .needs_iv = 0, .symmetric=1, .can_encrypt=1 }, + .needs_iv = 0, .is_symmetric=1, .can_encrypt=1, + .key_type = NCR_KEY_TYPE_SECRET }, { .algo = NCR_ALG_AES_ECB, .kstr = "ecb(aes)", - .needs_iv = 0, .symmetric=1, .can_encrypt=1 }, + .needs_iv = 0, .is_symmetric=1, .can_encrypt=1, + .key_type = NCR_KEY_TYPE_SECRET }, { .algo = NCR_ALG_CAMELLIA_ECB, .kstr = "ecb(camelia)", - .needs_iv = 0, .symmetric=1, .can_encrypt=1 }, + .needs_iv = 0, .is_symmetric=1, .can_encrypt=1, + .key_type = NCR_KEY_TYPE_SECRET }, { .algo = NCR_ALG_SHA1, .kstr = "sha1", - .digest_size = 20, .can_digest=1 }, + .digest_size = 20, .can_digest=1, + .key_type = NCR_KEY_TYPE_INVALID }, { .algo = NCR_ALG_MD5, .kstr = "md5", - .digest_size = 16, .can_digest=1 }, + .digest_size = 16, .can_digest=1, + .key_type = NCR_KEY_TYPE_INVALID }, { .algo = NCR_ALG_SHA2_224, .kstr = "sha224", - .digest_size = 28, .can_digest=1 }, + .digest_size = 28, .can_digest=1, + .key_type = NCR_KEY_TYPE_INVALID }, { .algo = NCR_ALG_SHA2_256, .kstr = "sha256", - .digest_size = 32, .can_digest=1 }, + .digest_size = 32, .can_digest=1, + .key_type = NCR_KEY_TYPE_INVALID }, { .algo = NCR_ALG_SHA2_384, .kstr = "sha384", - .digest_size = 48, .can_digest=1 }, + .digest_size = 48, .can_digest=1, + .key_type = NCR_KEY_TYPE_INVALID }, { .algo = NCR_ALG_SHA2_512, .kstr = "sha512", - .digest_size = 64, .can_digest=1 }, - { .algo = NCR_ALG_HMAC_SHA1, .hmac = 1, .kstr = "hmac(sha1)", - .digest_size = 20, .can_sign=1 }, - { .algo = NCR_ALG_HMAC_MD5, .hmac = 1, .kstr = "hmac(md5)", - .digest_size = 16, .can_sign=1 }, - { .algo = NCR_ALG_HMAC_SHA2_224, .hmac = 1, .kstr = "hmac(sha224)", - .digest_size = 28, .can_sign=1 }, - { .algo = NCR_ALG_HMAC_SHA2_256, .hmac = 1, .kstr = "hmac(sha256)", - .digest_size = 32, .can_sign=1 }, - { .algo = NCR_ALG_HMAC_SHA2_384, .hmac = 1, .kstr = "hmac(sha384)", - .digest_size = 48, .can_sign=1 }, - { .algo = NCR_ALG_HMAC_SHA2_512, .hmac = 1, .kstr = "hmac(sha512)", - .digest_size = 64, .can_sign=1 }, - { .algo = NCR_ALG_RSA, .kstr = NULL, - .can_encrypt=1, .can_sign=1}, - { .algo = NCR_ALG_DSA, .kstr = NULL, - .can_sign=1 }, + .digest_size = 64, .can_digest=1, + .key_type = NCR_KEY_TYPE_INVALID }, + { .algo = NCR_ALG_HMAC_SHA1, .is_hmac = 1, .kstr = "hmac(sha1)", + .digest_size = 20, .can_sign=1, + .key_type = NCR_KEY_TYPE_SECRET }, + { .algo = NCR_ALG_HMAC_MD5, .is_hmac = 1, .kstr = "hmac(md5)", + .digest_size = 16, .can_sign=1, + .key_type = NCR_KEY_TYPE_SECRET }, + { .algo = NCR_ALG_HMAC_SHA2_224, .is_hmac = 1, .kstr = "hmac(sha224)", + .digest_size = 28, .can_sign=1, + .key_type = NCR_KEY_TYPE_SECRET }, + { .algo = NCR_ALG_HMAC_SHA2_256, .is_hmac = 1, .kstr = "hmac(sha256)", + .digest_size = 32, .can_sign=1, + .key_type = NCR_KEY_TYPE_SECRET }, + { .algo = NCR_ALG_HMAC_SHA2_384, .is_hmac = 1, .kstr = "hmac(sha384)", + .digest_size = 48, .can_sign=1, + .key_type = NCR_KEY_TYPE_SECRET }, + { .algo = NCR_ALG_HMAC_SHA2_512, .is_hmac = 1, .kstr = "hmac(sha512)", + .digest_size = 64, .can_sign=1, + .key_type = NCR_KEY_TYPE_SECRET }, + { .algo = NCR_ALG_RSA, .kstr = NULL, .is_pk = 1, + .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_NONE } }; -const char* _ncr_algo_to_str(ncr_algorithm_t algo) +const struct algo_properties_st *_ncr_algo_to_properties(ncr_algorithm_t algo) { -ncr_algorithm_t a; -int i = 0; + ncr_algorithm_t a; + int i = 0; - while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { + for (i = 0; (a = algo_properties[i].algo) != NCR_ALG_NONE; i++) { if (a == algo) - return algo_properties[i].kstr; - i++; + return &algo_properties[i]; } return NULL; } -static int algo_needs_iv(ncr_algorithm_t algo) -{ -ncr_algorithm_t a; -int i = 0; - - while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { - if (a == algo) - return algo_properties[i].needs_iv; - i++; - } - - return 0; -} - -static int algo_can_sign(ncr_algorithm_t algo) -{ -ncr_algorithm_t a; -int i = 0; - - while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { - if (a == algo) - return algo_properties[i].can_sign; - i++; - } - - return 0; -} - -static int algo_can_encrypt(ncr_algorithm_t algo) -{ -ncr_algorithm_t a; -int i = 0; - - while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { - if (a == algo) - return algo_properties[i].can_encrypt; - i++; - } - - return 0; -} - -static int algo_can_digest(ncr_algorithm_t algo) -{ -ncr_algorithm_t a; -int i = 0; - - while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { - if (a == algo) - return algo_properties[i].can_digest; - i++; - } - - return 0; -} - - -static int algo_is_hmac(ncr_algorithm_t algo) -{ -ncr_algorithm_t a; -int i = 0; - - while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { - if (a == algo) - return algo_properties[i].hmac; - i++; - } - - return 0; -} - -static int algo_is_symmetric(ncr_algorithm_t algo) -{ -ncr_algorithm_t a; -int i = 0; - - while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { - if (a == algo) - return algo_properties[i].symmetric; - i++; - } - - return 0; -} - -int _ncr_algo_digest_size(ncr_algorithm_t algo) -{ -ncr_algorithm_t a; -int i = 0; - - while((a=algo_properties[i].algo)!=NCR_ALG_NONE) { - if (a == algo) - return algo_properties[i].digest_size; - i++; - } - - return 0; -} - static int _ncr_session_init(struct ncr_lists* lists, struct ncr_session_st* session) { struct session_item_st* ns = NULL; int ret; - ncr_algorithm_t sign_hash; - const char* str = NULL; + const struct algo_properties_st *sign_hash; ns = ncr_session_new(&lists->sessions); if (ns == NULL) { @@ -300,11 +227,17 @@ static int _ncr_session_init(struct ncr_lists* lists, struct ncr_session_st* ses } ns->op = session->op; - ns->algorithm = session->algorithm; + ns->algorithm = _ncr_algo_to_properties(session->algorithm); + if (ns->algorithm == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + switch(session->op) { case NCR_OP_ENCRYPT: case NCR_OP_DECRYPT: - if (algo_can_encrypt(session->algorithm)==0) { + if (!ns->algorithm->can_encrypt) { err(); ret = -EINVAL; goto fail; @@ -322,20 +255,19 @@ static int _ncr_session_init(struct ncr_lists* lists, struct ncr_session_st* ses if (session->algorithm == NCR_ALG_NULL) keysize = 0; - str = _ncr_algo_to_str(session->algorithm); - if (str == NULL) { + if (ns->algorithm->kstr == NULL) { err(); return -EINVAL; } - ret = cryptodev_cipher_init(&ns->cipher, str, + ret = cryptodev_cipher_init(&ns->cipher, ns->algorithm->kstr, ns->key->key.secret.data, keysize); if (ret < 0) { err(); goto fail; } - if (algo_needs_iv(session->algorithm)) { + if (ns->algorithm->needs_iv) { if (session->params.params.cipher.iv_size > sizeof(session->params.params.cipher.iv)) { err(); ret = -EINVAL; @@ -345,7 +277,7 @@ static int _ncr_session_init(struct ncr_lists* lists, struct ncr_session_st* ses } } else if (ns->key->type == NCR_KEY_TYPE_PRIVATE || ns->key->type == NCR_KEY_TYPE_PUBLIC) { ret = ncr_pk_cipher_init(ns->algorithm, &ns->pk, - &session->params, ns->key); + &session->params, ns->key, NULL); if (ret < 0) { err(); goto fail; @@ -359,89 +291,83 @@ static int _ncr_session_init(struct ncr_lists* lists, struct ncr_session_st* ses case NCR_OP_SIGN: case NCR_OP_VERIFY: - if (algo_can_sign(session->algorithm)==0) { + if (!ns->algorithm->can_sign && !ns->algorithm->can_digest) { err(); ret = -EINVAL; goto fail; } - /* read key */ - ret = ncr_key_item_get_read( &ns->key, &lists->key, session->key); - if (ret < 0) { - err(); - goto fail; - } - - if (ns->key->type == NCR_KEY_TYPE_SECRET) { - str = _ncr_algo_to_str(session->algorithm); - if (str == NULL) { - err(); - return -EINVAL; - } - - ret = cryptodev_hash_init(&ns->hash, str, 1, - ns->key->key.secret.data, ns->key->key.secret.size); - if (ret < 0) { + if (ns->algorithm->can_digest) { + if (ns->algorithm->kstr == NULL) { err(); + ret = -EINVAL; goto fail; } - } else if (ns->key->type == NCR_KEY_TYPE_PRIVATE || ns->key->type == NCR_KEY_TYPE_PUBLIC) { - ret = ncr_key_params_get_sign_hash(ns->key->algorithm, &session->params); + ret = cryptodev_hash_init(&ns->hash, ns->algorithm->kstr, 0, NULL, 0); if (ret < 0) { err(); - return ret; - } - sign_hash = ret; - - if (algo_can_digest(sign_hash) == 0) { - err(); - ret = -EINVAL; goto fail; } - str = _ncr_algo_to_str(sign_hash); - if (str == NULL) { - err(); - ret = -EINVAL; - goto fail; - } - - ret = ncr_pk_cipher_init(ns->algorithm, &ns->pk, - &session->params, ns->key); + + } else { + /* read key */ + ret = ncr_key_item_get_read( &ns->key, &lists->key, session->key); if (ret < 0) { err(); goto fail; } - ret = cryptodev_hash_init(&ns->hash, str, 0, NULL, 0); - if (ret < 0) { + if (ns->algorithm->is_hmac && ns->key->type == NCR_KEY_TYPE_SECRET) { + if (ns->algorithm->kstr == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + ret = cryptodev_hash_init(&ns->hash, ns->algorithm->kstr, 1, + ns->key->key.secret.data, ns->key->key.secret.size); + if (ret < 0) { + err(); + goto fail; + } + + } else if (ns->algorithm->is_pk && (ns->key->type == NCR_KEY_TYPE_PRIVATE || ns->key->type == NCR_KEY_TYPE_PUBLIC)) { + sign_hash = ncr_key_params_get_sign_hash(ns->key->algorithm, &session->params); + if (IS_ERR(sign_hash)) { + err(); + return PTR_ERR(sign_hash); + } + + if (!sign_hash->can_digest) { + err(); + ret = -EINVAL; + goto fail; + } + + if (sign_hash->kstr == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + + ret = ncr_pk_cipher_init(ns->algorithm, &ns->pk, + &session->params, ns->key, sign_hash); + if (ret < 0) { + err(); + goto fail; + } + + ret = cryptodev_hash_init(&ns->hash, sign_hash->kstr, 0, NULL, 0); + if (ret < 0) { + err(); + goto fail; + } + } else { err(); + ret = -EINVAL; goto fail; } - } else { - err(); - ret = -EINVAL; - goto fail; - } - - break; - case NCR_OP_DIGEST: - if (algo_can_digest(session->algorithm)==0) { - err(); - ret = -EINVAL; - goto fail; - } - str = _ncr_algo_to_str(session->algorithm); - if (str == NULL) { - err(); - ret = -EINVAL; - goto fail; - } - - ret = cryptodev_hash_init(&ns->hash, str, 0, NULL, 0); - if (ret < 0) { - err(); - goto fail; } break; @@ -487,14 +413,223 @@ int ncr_session_init(struct ncr_lists* lists, void __user* arg) return ret; } -/* Main update function - */ -static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st* op) +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; + + if (sess->algorithm->is_symmetric) { + /* read key */ + ret = cryptodev_cipher_encrypt(&sess->cipher, input, + output, input_size); + if (ret < 0) { + err(); + return ret; + } + /* FIXME: handle ciphers that do not require that */ + + } else { /* public key */ + ret = ncr_pk_cipher_encrypt(&sess->pk, input, input_cnt, input_size, + output, output_cnt, output_size); + + if (ret < 0) { + err(); + return ret; + } + } + + return 0; +} + +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) +{ +int ret; + + if (sess->algorithm->is_symmetric) { + /* read key */ + ret = cryptodev_cipher_decrypt(&sess->cipher, input, + output, input_size); + if (ret < 0) { + err(); + return ret; + } + /* FIXME: handle ciphers that do not require equality */ + + } else { /* public key */ + ret = ncr_pk_cipher_decrypt(&sess->pk, input, input_cnt, input_size, + output, output_cnt, output_size); + + if (ret < 0) { + err(); + return ret; + } + } + + return 0; +} + +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, + void __user * udata, size_t udata_size, struct scatterlist **dst_sg, unsigned *dst_cnt) +{ + int pagecount = 0; + + if (unlikely(udata == NULL)) { + err(); + 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; + } + } + + if (__get_userbuf(udata, udata_size, 1, + pagecount, ses->pages, ses->sg)) { + err(); + return -EINVAL; + } + (*dst_sg) = ses->sg; + *dst_cnt = pagecount; + + ses->available_pages = 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; + size_t input_size = op->data.udata.input_size; + + if (unlikely(op->data.udata.input == NULL)) { + err(); + 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 */ + write_src = 0; + if (op->data.udata.output != NULL) { + dst_pagecount = PAGECOUNT(op->data.udata.output, op->data.udata.output_size); + } else { + dst_pagecount = 0; + } + } else { + src_pagecount = max((int)(PAGECOUNT(op->data.udata.output, op->data.udata.output_size)), + src_pagecount); + input_size = max(input_size, (size_t)op->data.udata.output_size); + } + + 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, input_size, write_src, + src_pagecount, ses->pages, ses->sg)) { + err(); + printk("write: %d\n", write_src); + 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)) { + err(); + 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; + } + } + + ses->available_pages = pagecount; + + return 0; +} + +/* Called when userspace buffers are used */ +int _ncr_session_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; + 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) { @@ -502,131 +637,68 @@ static int _ncr_session_update(struct ncr_lists* lists, struct ncr_session_op_st 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: - /* obtain data item */ - data = ncr_data_item_get( &lists->data, op->data.cipher.plaintext); - if (data == NULL) { - err(); - ret = -EINVAL; - goto fail; - } - - odata = ncr_data_item_get( &lists->data, op->data.cipher.ciphertext); - if (odata == NULL) { + if (osg == NULL) { err(); ret = -EINVAL; goto fail; } - if (odata->max_data_size < data->data_size) { + ret = _ncr_session_encrypt(sess, isg, isg_cnt, isg_size, + osg, osg_cnt, &osg_size); + if (ret < 0) { err(); - ret = -EINVAL; goto fail; } + op->data.udata.output_size = osg_size; - if (algo_is_symmetric(sess->algorithm)) { - /* read key */ - ret = _cryptodev_cipher_encrypt(&sess->cipher, data->data, - data->data_size, odata->data, data->data_size); - if (ret < 0) { - err(); - goto fail; - } - /* FIXME: handle ciphers that do not require that */ - odata->data_size = data->data_size; - } else { /* public key */ - size_t new_size = odata->max_data_size; - ret = ncr_pk_cipher_encrypt(&sess->pk, data->data, data->data_size, - odata->data, &new_size); - - odata->data_size = new_size; - - if (ret < 0) { - err(); - goto fail; - } - } break; case NCR_OP_DECRYPT: - /* obtain data item */ - data = ncr_data_item_get( &lists->data, op->data.cipher.ciphertext); - if (data == NULL) { + if (osg == NULL) { err(); ret = -EINVAL; goto fail; } - odata = ncr_data_item_get( &lists->data, op->data.cipher.plaintext); - if (odata == NULL) { + if (osg_size < isg_size) { err(); ret = -EINVAL; goto fail; } - if (odata->max_data_size < data->data_size) { + ret = _ncr_session_decrypt(sess, isg, isg_cnt, isg_size, + osg, osg_cnt, &osg_size); + if (ret < 0) { err(); - ret = -EINVAL; goto fail; } - - /* read key */ - if (algo_is_symmetric(sess->algorithm)) { - ret = _cryptodev_cipher_decrypt(&sess->cipher, data->data, data->data_size, odata->data, data->data_size); - if (ret < 0) { - err(); - goto fail; - } - /* FIXME: handle ciphers that do not require that */ - odata->data_size = data->data_size; - } else { /* public key */ - size_t new_size = odata->max_data_size; - ret = ncr_pk_cipher_decrypt(&sess->pk, data->data, data->data_size, - odata->data, &new_size); - - odata->data_size = new_size; - - if (ret < 0) { - err(); - goto fail; - } - } + op->data.udata.output_size = osg_size; break; case NCR_OP_SIGN: - case NCR_OP_DIGEST: - /* obtain data item */ - data = ncr_data_item_get( &lists->data, op->data.sign.text); - if (data == NULL) { - err(); - ret = -EINVAL; - goto fail; - } - - ret = _cryptodev_hash_update(&sess->hash, data->data, data->data_size); - if (ret < 0) { - err(); - goto fail; - } - break; - case NCR_OP_VERIFY: - /* obtain data item */ - data = ncr_data_item_get( &lists->data, op->data.verify.text); - if (data == NULL) { - err(); - ret = -EINVAL; - goto fail; - } - - ret = _cryptodev_hash_update(&sess->hash, data->data, data->data_size); + ret = cryptodev_hash_update(&sess->hash, isg, isg_size); if (ret < 0) { err(); goto fail; } break; - default: err(); ret = -EINVAL; @@ -636,51 +708,42 @@ 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; } -int ncr_session_update(struct ncr_lists* lists, void __user* arg) +static int try_session_update(struct ncr_lists* lists, struct ncr_session_op_st* op) { - struct ncr_session_op_st op; - - if (unlikely(copy_from_user( &op, arg, sizeof(op)))) { - err(); - return -EFAULT; + if (op->type == NCR_KEY_DATA) { + if (op->data.kdata.input != NCR_KEY_INVALID) + return _ncr_session_update_key(lists, op); + } else if (op->type == NCR_DIRECT_DATA) { + if (op->data.udata.input != NULL) + return _ncr_session_update(lists, op); } - - return _ncr_session_update(lists, &op); -} - -static 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; + return 0; } -static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* op) +int _ncr_session_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; + void __user * udata = NULL; + size_t *udata_size; sess = ncr_sessions_item_get( &lists->sessions, op->ses); if (sess == NULL) { @@ -688,32 +751,42 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* return -EINVAL; } + ret = try_session_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; + } + + if (op->type == NCR_DIRECT_DATA) { + udata = op->data.udata.output; + udata_size = &op->data.udata.output_size; + } else if (op->type == NCR_KEY_DATA) { + udata = op->data.kdata.output; + udata_size = &op->data.kdata.output_size; + } else { + err(); + ret = -EINVAL; + goto fail; + } + switch(sess->op) { case NCR_OP_ENCRYPT: case NCR_OP_DECRYPT: - /* obtain data item */ - if (op->data.cipher.plaintext != NCR_DATA_INVALID && - op->data.cipher.ciphertext != NCR_DATA_INVALID) { - ret = _ncr_session_update(lists, op); - if (ret < 0) - goto fail; - } break; - case NCR_OP_VERIFY: - /* obtain data item */ - if (op->data.sign.text != NCR_DATA_INVALID) { - ret = _ncr_session_update(lists, op); - if (ret < 0) - goto fail; - } - - odata = ncr_data_item_get( &lists->data, op->data.verify.signature); - if (odata == NULL) { + ret = get_userbuf1(sess, udata, *udata_size, &osg, &osg_cnt); + if (ret < 0) { err(); - ret = -EINVAL; goto fail; } + orig_osg_size = osg_size = *udata_size; digest_size = sess->hash.digestsize; if (digest_size == 0 || sizeof(digest) < digest_size) { @@ -726,11 +799,17 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* err(); goto fail; } - - if (algo_is_hmac(sess->algorithm)) { - if (digest_size != odata->data_size || - memcmp(odata->data, digest, digest_size) != 0) { + 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 != osg_size || + memcmp(vdigest, digest, digest_size) != 0) { op->err = NCR_VERIFICATION_FAILED; } else { @@ -738,7 +817,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->data, odata->data_size, + ret = ncr_pk_cipher_verify(&sess->pk, osg, osg_cnt, osg_size, digest, digest_size, &op->err); if (ret < 0) { err(); @@ -748,41 +827,46 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* break; case NCR_OP_SIGN: - case NCR_OP_DIGEST: - /* obtain data item */ - if (op->data.sign.text != NCR_DATA_INVALID) { - ret = _ncr_session_update(lists, op); - if (ret < 0) - goto fail; + ret = get_userbuf1(sess, udata, *udata_size, &osg, &osg_cnt); + if (ret < 0) { + err(); + goto fail; } - odata = ncr_data_item_get( &lists->data, op->data.sign.output); - if (odata == NULL) { + orig_osg_size = osg_size = *udata_size; + + digest_size = sess->hash.digestsize; + if (digest_size == 0 || osg_size < digest_size) { err(); ret = -EINVAL; goto fail; } - digest_size = sess->hash.digestsize; - if (digest_size == 0 || odata->max_data_size < digest_size) { + 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->op != NCR_OP_DIGEST && !algo_is_hmac(sess->algorithm)) { + if (sess->algorithm->is_pk) { /* PK signature */ - size_t new_size = odata->max_data_size; - ret = ncr_pk_cipher_sign(&sess->pk, odata->data, odata->data_size, - odata->data, &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: @@ -791,12 +875,20 @@ static int _ncr_session_final(struct ncr_lists* lists, struct ncr_session_op_st* goto fail; } + if (osg_size > 0) + *udata_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 (algo_is_symmetric(sess->algorithm)) { + if (sess->algorithm->is_symmetric) { cryptodev_cipher_deinit(&sess->cipher); } else { ncr_pk_cipher_deinit(&sess->pk); @@ -808,6 +900,93 @@ fail: return ret; } +/* Direct with key: Allows to hash a key */ +/* Called when userspace buffers are used */ +static int _ncr_session_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; + + 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; + } + + 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 (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; + int ret; + + if (unlikely(copy_from_user( &op, arg, sizeof(op)))) { + err(); + return -EFAULT; + } + + if (op.type == NCR_DIRECT_DATA) + ret = _ncr_session_update(lists, &op); + else if (op.type == NCR_KEY_DATA) + ret = _ncr_session_update_key(lists, &op); + else + ret = -EINVAL; + + if (unlikely(ret)) { + err(); + return ret; + } + + if (unlikely(copy_to_user(arg, &op, sizeof(op)))) { + err(); + return -EFAULT; + } + + return 0; +} + int ncr_session_final(struct ncr_lists* lists, void __user* arg) { struct ncr_session_op_st op; @@ -858,4 +1037,3 @@ int ncr_session_once(struct ncr_lists* lists, void __user* arg) return -EFAULT; return 0; } - |