diff options
author | Miloslav Trmač <mitr@redhat.com> | 2010-08-25 05:20:11 +0200 |
---|---|---|
committer | Miloslav Trmač <mitr@redhat.com> | 2010-08-25 06:04:02 +0200 |
commit | 56895fcb6ada286ee95df0e49076f2785c45a0db (patch) | |
tree | eaf78f5b0c1310ddc053e7a47bb2a41001d5e44e | |
parent | db7c441175942d3b3c3e6321a9a16dc7e83b747c (diff) | |
download | cryptodev-linux-56895fcb6ada286ee95df0e49076f2785c45a0db.tar.gz cryptodev-linux-56895fcb6ada286ee95df0e49076f2785c45a0db.tar.xz cryptodev-linux-56895fcb6ada286ee95df0e49076f2785c45a0db.zip |
Implement cloning hash sessions
-rw-r--r-- | crypto.4 | 10 | ||||
-rw-r--r-- | cryptodev_cipher.c | 42 | ||||
-rw-r--r-- | cryptodev_int.h | 2 | ||||
-rw-r--r-- | ncr-sessions.c | 97 |
4 files changed, 134 insertions, 17 deletions
@@ -520,13 +520,18 @@ The following input attributes are recognized: .RS .IP \fBNCR_ATTR_ALGORITHM\fP -Mandatory. +Mandatory unless +.B NCR_ATTR_SESSION_CLONE_FROM +is provided. .IP \fBNCR_ATTR_IV\fP Mandatory for some operations and algorithms. .IP \fBNCR_ATTR_KEY\fP Mandatory for some operations and algorithms. An 32-bit unsigned integer in native byte order specifying the key to use for the operation. +If +.B NCR_ATTR_SESSION_CLONE_FROM +is provided, the key from the original session is used. .IP \fBNCR_ATTR_RSA_ENCODING_METHOD\fP Mandatory for RSA. An 32-bit unsigned integer in native byte order @@ -546,8 +551,7 @@ Optional, defaults to 0. .IP \fBNCR_ATTR_SESSION_CLONE_FROM\fP Optional, a 32-bit unsigned integer in native byte order specifying session state to clone. -Only supported for some operations and algorithms; -specifically intended for cloning hashing sessions. +Only supported for some operations and algorithms. .IP \fBNCR_ATTR_SIGNATURE_HASH_ALGORITHM\fP Mandatory for some operations and algorithms. A NUL-terminated string specifying a hash algorithm underlying a signature, diff --git a/cryptodev_cipher.c b/cryptodev_cipher.c index dae4a63..1fb1147 100644 --- a/cryptodev_cipher.c +++ b/cryptodev_cipher.c @@ -278,6 +278,48 @@ error: return ret; } +int cryptodev_hash_clone(struct hash_data *hdata, struct hash_data *old_data, + const void *mackey, size_t mackeylen) +{ + const char *algo; + void *state; + int ret; + + /* We want exactly the same driver. */ + algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(old_data->async.s)); + ret = cryptodev_hash_init(hdata, algo, mackey, mackeylen); + if (unlikely(ret != 0)) + return ret; + + state = kmalloc(crypto_ahash_statesize(hdata->async.s), GFP_KERNEL); + if (unlikely(state == NULL)) { + ret = -ENOMEM; + goto err; + } + + ret = crypto_ahash_export(old_data->async.request, state); + if (unlikely(ret != 0)) { + dprintk(0, KERN_ERR, "error exporting hash state\n"); + goto err; + } + ret = crypto_ahash_import(hdata->async.request, state); + if (unlikely(ret != 0)) { + dprintk(0,KERN_ERR, + "error in crypto_hash_init()\n"); + goto err; + } + + kfree(state); + + hdata->init = 1; + return 0; + +err: + kfree(state); + cryptodev_hash_deinit(hdata); + return ret; +} + void cryptodev_hash_deinit(struct hash_data* hdata) { if (hdata->init) { diff --git a/cryptodev_int.h b/cryptodev_int.h index 573fcaa..4b140ba 100644 --- a/cryptodev_int.h +++ b/cryptodev_int.h @@ -78,5 +78,7 @@ ssize_t _cryptodev_hash_update( struct hash_data* hdata, const void* data, size_ int cryptodev_hash_reset( struct hash_data* hdata); void cryptodev_hash_deinit(struct hash_data* hdata); int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name, const void *mackey, size_t mackeylen); +int cryptodev_hash_clone(struct hash_data *hdata, struct hash_data *old_data, + const void *mackey, size_t mackeylen); #endif /* CRYPTODEV_INT_H */ diff --git a/ncr-sessions.c b/ncr-sessions.c index a08f237..aa9026d 100644 --- a/ncr-sessions.c +++ b/ncr-sessions.c @@ -334,13 +334,38 @@ static int key_item_get_nla_read(struct key_item_st **st, return ret; } +/* The caller is responsible for locking of "session". old_session must not be + locked on entry. */ +static int +init_or_clone_hash(struct session_item_st *session, + struct session_item_st *old_session, + const struct algo_properties_st *algo, + const void *mac_key, size_t mac_key_size) +{ + int ret; + + if (old_session == NULL) + return cryptodev_hash_init(&session->hash, algo->kstr, + mac_key, mac_key_size); + + if (mutex_lock_interruptible(&old_session->mutex)) { + err(); + return -ERESTARTSYS; + } + ret = cryptodev_hash_clone(&session->hash, &old_session->hash, mac_key, + mac_key_size); + mutex_unlock(&old_session->mutex); + + return ret; +} + static struct session_item_st *_ncr_session_init(struct ncr_lists *lists, ncr_session_t desc, ncr_crypto_op_t op, struct nlattr *tb[]) { const struct nlattr *nla; - struct session_item_st *ns; + struct session_item_st *ns, *old_session = NULL; int ret; const struct algo_properties_st *sign_hash; @@ -353,12 +378,31 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists, is necessary. */ ns->op = op; - ns->algorithm = _ncr_nla_to_properties(tb[NCR_ATTR_ALGORITHM]); - if (ns->algorithm == NULL) { - err(); - ret = -EINVAL; - goto fail; + nla = tb[NCR_ATTR_SESSION_CLONE_FROM]; + if (nla != NULL) { + /* "ns" is not visible to userspace, so this is safe. */ + old_session = session_get_ref(lists, nla_get_u32(nla)); + if (old_session == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + if (ns->op != old_session->op) { + err(); + ret = -EINVAL; + goto fail; + } } + + if (old_session == NULL) { + ns->algorithm = _ncr_nla_to_properties(tb[NCR_ATTR_ALGORITHM]); + if (ns->algorithm == NULL) { + err(); + ret = -EINVAL; + goto fail; + } + } else + ns->algorithm = old_session->algorithm; switch(op) { case NCR_OP_ENCRYPT: @@ -369,6 +413,12 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists, goto fail; } + if (old_session != NULL) { + err(); + ret = -EOPNOTSUPP; + goto fail; + } + /* read key */ ret = key_item_get_nla_read(&ns->key, lists, tb[NCR_ATTR_KEY]); @@ -444,19 +494,27 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists, goto fail; } - ret = cryptodev_hash_init(&ns->hash, ns->algorithm->kstr, NULL, 0); + ret = init_or_clone_hash(ns, old_session, + ns->algorithm, NULL, + 0); if (ret < 0) { err(); goto fail; } } else { - /* read key */ - ret = key_item_get_nla_read(&ns->key, lists, - tb[NCR_ATTR_KEY]); - if (ret < 0) { - err(); - goto fail; + /* Get key */ + if (old_session == NULL) { + ret = key_item_get_nla_read(&ns->key, + lists, + tb[NCR_ATTR_KEY]); + if (ret < 0) { + err(); + goto fail; + } + } else { + atomic_inc(&old_session->key->refcnt); + ns->key = old_session->key; } /* wrapping keys cannot be used for anything except wrapping. @@ -474,7 +532,7 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists, goto fail; } - ret = cryptodev_hash_init(&ns->hash, ns->algorithm->kstr, + ret = init_or_clone_hash(ns, old_session, ns->algorithm, ns->key->key.secret.data, ns->key->key.secret.size); if (ret < 0) { err(); @@ -482,6 +540,12 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists, } } else if (ns->algorithm->is_pk && (ns->key->type == NCR_KEY_TYPE_PRIVATE || ns->key->type == NCR_KEY_TYPE_PUBLIC)) { + if (old_session != NULL) { + err(); + ret = -EOPNOTSUPP; + goto fail; + } + nla = tb[NCR_ATTR_SIGNATURE_HASH_ALGORITHM]; sign_hash = _ncr_nla_to_properties(nla); if (sign_hash == NULL) { @@ -527,10 +591,15 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists, ret = -EINVAL; goto fail; } + + if (old_session != NULL) + _ncr_sessions_item_put(old_session); return ns; fail: + if (old_session != NULL) + _ncr_sessions_item_put(old_session); _ncr_sessions_item_put(ns); return ERR_PTR(ret); |