summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiloslav Trmač <mitr@redhat.com>2010-08-25 06:06:16 +0200
committerMiloslav Trmač <mitr@redhat.com>2010-08-25 06:06:16 +0200
commitf90894ca4a2f56c42b787504e59421b89030c75e (patch)
tree912392aa002babcafa3b54266f85e203e89d6990
parent7f6e65351ae2c214f28496609103711773721ca5 (diff)
parent5d586cad2979ad279e9a7f0985d008e5d649bbc5 (diff)
downloadcryptodev-linux-f90894ca4a2f56c42b787504e59421b89030c75e.tar.gz
cryptodev-linux-f90894ca4a2f56c42b787504e59421b89030c75e.tar.xz
cryptodev-linux-f90894ca4a2f56c42b787504e59421b89030c75e.zip
Merge branch 'clone-session'
Conflicts: cryptodev_int.h ncr-sessions.c
-rw-r--r--crypto.411
-rw-r--r--cryptodev_cipher.c42
-rw-r--r--cryptodev_int.h2
-rw-r--r--examples/ncr.c218
-rw-r--r--ncr-sessions.c97
-rw-r--r--ncr.h1
-rw-r--r--utils.c1
7 files changed, 357 insertions, 15 deletions
diff --git a/crypto.4 b/crypto.4
index 0dc21e9..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
@@ -543,6 +548,10 @@ For RSA with \fBRSA_PKCS1_PSS\fP.
An 32-bit unsigned integer in native byte order
specifying the PSS salt length.
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.
.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/examples/ncr.c b/examples/ncr.c
index a7d34f0..2039516 100644
--- a/examples/ncr.c
+++ b/examples/ncr.c
@@ -1237,6 +1237,221 @@ test_ncr_hash(int cfd)
}
static int
+test_ncr_hash_clone(int cfd)
+{
+ ncr_key_t key;
+ struct __attribute__((packed)) {
+ struct ncr_key_import f;
+ struct nlattr id_head ALIGN_NL;
+ uint8_t id[2] ALIGN_NL;
+ struct nlattr type_head ALIGN_NL;
+ uint32_t type ALIGN_NL;
+ struct nlattr flags_head ALIGN_NL;
+ uint32_t flags ALIGN_NL;
+ struct nlattr algo_head ALIGN_NL;
+ char algo[128] ALIGN_NL;
+ } kimport;
+ uint8_t data[HASH_DATA_SIZE];
+ const struct hash_vectors_st *hv;
+ int j;
+ size_t data_size;
+ struct __attribute__((packed)) {
+ struct ncr_session_init f;
+ struct nlattr key_head ALIGN_NL;
+ uint32_t key ALIGN_NL;
+ struct nlattr algo_head ALIGN_NL;
+ char algo[128] ALIGN_NL;
+ } kinit;
+ struct __attribute__((packed)) {
+ struct ncr_session_update f;
+ struct nlattr input_head ALIGN_NL;
+ struct ncr_session_input_data input ALIGN_NL;
+ } kupdate;
+ struct __attribute__((packed)) {
+ struct ncr_session_final f;
+ struct nlattr input_head ALIGN_NL;
+ struct ncr_session_input_data input ALIGN_NL;
+ struct nlattr output_head ALIGN_NL;
+ struct ncr_session_output_buffer output ALIGN_NL;
+ } kfinal;
+ struct __attribute__((packed)) {
+ struct ncr_session_once f;
+ struct nlattr clone_head ALIGN_NL;
+ uint32_t clone ALIGN_NL;
+ struct nlattr input_head ALIGN_NL;
+ struct ncr_session_input_data input ALIGN_NL;
+ struct nlattr output_head ALIGN_NL;
+ struct ncr_session_output_buffer output ALIGN_NL;
+ } kclone;
+ ncr_session_t ses;
+
+ /* convert it to key */
+ key = ioctl(cfd, NCRIO_KEY_INIT);
+ if (key == -1) {
+ perror("ioctl(NCRIO_KEY_INIT)");
+ return 1;
+ }
+
+ fprintf(stdout, "Tests of hash cloning\n");
+ for (hv = hash_vectors;
+ hv < hash_vectors + sizeof(hash_vectors) / sizeof(hash_vectors[0]);
+ hv++) {
+ size_t algo_size;
+
+ algo_size = strlen(hv->algorithm) + 1;
+ fprintf(stdout, "\t%s:\n", hv->algorithm);
+ /* import key */
+ if (hv->key != NULL) {
+
+ memset(&kimport.f, 0, sizeof(kimport.f));
+ kimport.f.key = key;
+ kimport.f.data = hv->key;
+ kimport.f.data_size = hv->key_size;
+ kimport.id_head.nla_len
+ = NLA_HDRLEN + sizeof(kimport.id);
+ kimport.id_head.nla_type = NCR_ATTR_KEY_ID;
+ kimport.id[0] = 'a';
+ kimport.id[1] = 'b';
+ kimport.type_head.nla_len
+ = NLA_HDRLEN + sizeof(kimport.type);
+ kimport.type_head.nla_type = NCR_ATTR_KEY_TYPE;
+ kimport.type = NCR_KEY_TYPE_SECRET;
+ kimport.flags_head.nla_len
+ = NLA_HDRLEN + sizeof(kimport.flags);
+ kimport.flags_head.nla_type = NCR_ATTR_KEY_FLAGS;
+ kimport.flags = NCR_KEY_FLAG_EXPORTABLE;
+ kimport.algo_head.nla_len = NLA_HDRLEN + algo_size;
+ kimport.algo_head.nla_type = NCR_ATTR_ALGORITHM;
+ memcpy(kimport.algo, hv->algorithm, algo_size);
+ kimport.f.input_size
+ = kimport.algo + algo_size - (char *)&kimport;
+ if (ioctl(cfd, NCRIO_KEY_IMPORT, &kimport)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_KEY_IMPORT)");
+ return 1;
+ }
+ }
+
+ /* Initialize a session */
+ memset(&kinit.f, 0, sizeof(kinit.f));
+ kinit.f.op = hv->op;
+ kinit.key_head.nla_len = NLA_HDRLEN + sizeof(kinit.key);
+ kinit.key_head.nla_type = NCR_ATTR_KEY;
+ kinit.key = hv->key != NULL ? key : NCR_KEY_INVALID;
+ kinit.algo_head.nla_len = NLA_HDRLEN + algo_size;
+ kinit.algo_head.nla_type = NCR_ATTR_ALGORITHM;
+ memcpy(kinit.algo, hv->algorithm, algo_size);
+ kinit.f.input_size = kinit.algo + algo_size - (char *)&kinit;
+
+ ses = ioctl(cfd, NCRIO_SESSION_INIT, &kinit);
+ if (ses < 0) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_SESSION_INIT)");
+ return 1;
+ }
+
+ /* Submit half of the data */
+ memset(&kupdate.f, 0, sizeof(kupdate.f));
+ kupdate.f.input_size = sizeof(kupdate);
+ kupdate.f.ses = ses;
+ kupdate.input_head.nla_len = NLA_HDRLEN + sizeof(kupdate.input);
+ kupdate.input_head.nla_type = NCR_ATTR_UPDATE_INPUT_DATA;
+ kupdate.input.data = hv->plaintext;
+ kupdate.input.data_size = hv->plaintext_size / 2;
+
+ if (ioctl(cfd, NCRIO_SESSION_UPDATE, &kupdate)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_SESSION_UPDATE)");
+ return 1;
+ }
+
+ /* Clone a session, submit the other half, verify. */
+ memset(&kclone.f, 0, sizeof(kclone.f));
+ kclone.f.input_size = sizeof(kclone);
+ kclone.f.op = hv->op;
+ kclone.clone_head.nla_len = NLA_HDRLEN + sizeof(kclone.clone);
+ kclone.clone_head.nla_type = NCR_ATTR_SESSION_CLONE_FROM;
+ kclone.clone = ses;
+ kclone.input_head.nla_len = NLA_HDRLEN + sizeof(kclone.input);
+ kclone.input_head.nla_type = NCR_ATTR_UPDATE_INPUT_DATA;
+ kclone.input.data = hv->plaintext + hv->plaintext_size / 2;
+ kclone.input.data_size
+ = hv->plaintext_size - hv->plaintext_size / 2;
+ kclone.output_head.nla_len = NLA_HDRLEN + sizeof(kclone.output);
+ kclone.output_head.nla_type = NCR_ATTR_FINAL_OUTPUT_BUFFER;
+ kclone.output.buffer = data;
+ kclone.output.buffer_size = sizeof(data);
+ kclone.output.result_size_ptr = &data_size;
+
+ if (ioctl(cfd, NCRIO_SESSION_ONCE, &kclone)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_SESSION_ONCE)");
+ return 1;
+ }
+
+ if (data_size != hv->output_size
+ || memcmp(data, hv->output, hv->output_size) != 0) {
+ fprintf(stderr, "HASH test vector %td failed!\n",
+ hv - hash_vectors);
+
+ fprintf(stderr, "Output[%zu]: ", data_size);
+ for(j = 0; j < data_size; j++)
+ fprintf(stderr, "%.2x:", (int)data[j]);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "Expected[%d]: ", hv->output_size);
+ for (j = 0; j < hv->output_size; j++)
+ fprintf(stderr, "%.2x:", (int)hv->output[j]);
+ fprintf(stderr, "\n");
+ return 1;
+ }
+
+ /* Submit the other half to the original session, verify. */
+ memset(&kfinal.f, 0, sizeof(kfinal.f));
+ kfinal.f.input_size = sizeof(kfinal);
+ kfinal.f.ses = ses;
+ kfinal.input_head.nla_len = NLA_HDRLEN + sizeof(kfinal.input);
+ kfinal.input_head.nla_type = NCR_ATTR_UPDATE_INPUT_DATA;
+ kfinal.input.data = hv->plaintext + hv->plaintext_size / 2;
+ kfinal.input.data_size
+ = hv->plaintext_size - hv->plaintext_size / 2;
+ kfinal.output_head.nla_len = NLA_HDRLEN + sizeof(kfinal.output);
+ kfinal.output_head.nla_type = NCR_ATTR_FINAL_OUTPUT_BUFFER;
+ kfinal.output.buffer = data;
+ kfinal.output.buffer_size = sizeof(data);
+ kfinal.output.result_size_ptr = &data_size;
+
+ if (ioctl(cfd, NCRIO_SESSION_FINAL, &kfinal)) {
+ fprintf(stderr, "Error: %s:%d\n", __func__, __LINE__);
+ perror("ioctl(NCRIO_SESSION_FINAL)");
+ return 1;
+ }
+
+ if (data_size != hv->output_size
+ || memcmp(data, hv->output, hv->output_size) != 0) {
+ fprintf(stderr, "HASH test vector %td failed!\n",
+ hv - hash_vectors);
+
+ fprintf(stderr, "Output[%zu]: ", data_size);
+ for(j = 0; j < data_size; j++)
+ fprintf(stderr, "%.2x:", (int)data[j]);
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "Expected[%d]: ", hv->output_size);
+ for (j = 0; j < hv->output_size; j++)
+ fprintf(stderr, "%.2x:", (int)hv->output[j]);
+ fprintf(stderr, "\n");
+ return 1;
+ }
+ }
+
+ fprintf(stdout, "\n");
+
+ return 0;
+
+}
+
+static int
test_ncr_hash_key(int cfd)
{
ncr_key_t key;
@@ -1415,6 +1630,9 @@ main()
if (test_ncr_hash(fd))
return 1;
+ if (test_ncr_hash_clone(fd))
+ return 1;
+
if (test_ncr_hash_key(fd))
return 1;
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);
diff --git a/ncr.h b/ncr.h
index 47981d1..3c416eb 100644
--- a/ncr.h
+++ b/ncr.h
@@ -58,6 +58,7 @@ enum {
NCR_ATTR_DH_BASE, /* NLA_BINARY */
NCR_ATTR_DH_PUBLIC, /* NLA_BINARY */
NCR_ATTR_WANTED_ATTRS, /* NLA_BINARY - array of u16 IDs */
+ NCR_ATTR_SESSION_CLONE_FROM, /* NLA_U32 - ncr_session_t */
/* Add new attributes here */
diff --git a/utils.c b/utils.c
index 514833c..a427833 100644
--- a/utils.c
+++ b/utils.c
@@ -82,6 +82,7 @@ static const struct nla_policy ncr_attr_policy[NCR_ATTR_MAX + 1] = {
[NCR_ATTR_DH_BASE] = { NLA_BINARY, 0 },
[NCR_ATTR_DH_PUBLIC] = { NLA_BINARY, 0 },
[NCR_ATTR_WANTED_ATTRS] = { NLA_BINARY, 0 },
+ [NCR_ATTR_SESSION_CLONE_FROM] = { NLA_U32, 0 },
};
void *__ncr_get_input_args(void *fixed, struct nlattr *tb[], size_t fixed_size,