summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiloslav Trmač <mitr@redhat.com>2010-08-25 05:20:11 +0200
committerMiloslav Trmač <mitr@redhat.com>2010-08-25 06:04:02 +0200
commit56895fcb6ada286ee95df0e49076f2785c45a0db (patch)
treeeaf78f5b0c1310ddc053e7a47bb2a41001d5e44e
parentdb7c441175942d3b3c3e6321a9a16dc7e83b747c (diff)
downloadcryptodev-linux-56895fcb6ada286ee95df0e49076f2785c45a0db.tar.gz
cryptodev-linux-56895fcb6ada286ee95df0e49076f2785c45a0db.tar.xz
cryptodev-linux-56895fcb6ada286ee95df0e49076f2785c45a0db.zip
Implement cloning hash sessions
-rw-r--r--crypto.410
-rw-r--r--cryptodev_cipher.c42
-rw-r--r--cryptodev_int.h2
-rw-r--r--ncr-sessions.c97
4 files changed, 134 insertions, 17 deletions
diff --git a/crypto.4 b/crypto.4
index 04d952e..c1b39e1 100644
--- a/crypto.4
+++ b/crypto.4
@@ -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);