diff options
author | Miloslav Trmač <mitr@redhat.com> | 2010-08-25 06:06:16 +0200 |
---|---|---|
committer | Miloslav Trmač <mitr@redhat.com> | 2010-08-25 06:06:16 +0200 |
commit | f90894ca4a2f56c42b787504e59421b89030c75e (patch) | |
tree | 912392aa002babcafa3b54266f85e203e89d6990 | |
parent | 7f6e65351ae2c214f28496609103711773721ca5 (diff) | |
parent | 5d586cad2979ad279e9a7f0985d008e5d649bbc5 (diff) | |
download | cryptodev-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.4 | 11 | ||||
-rw-r--r-- | cryptodev_cipher.c | 42 | ||||
-rw-r--r-- | cryptodev_int.h | 2 | ||||
-rw-r--r-- | examples/ncr.c | 218 | ||||
-rw-r--r-- | ncr-sessions.c | 97 | ||||
-rw-r--r-- | ncr.h | 1 | ||||
-rw-r--r-- | utils.c | 1 |
7 files changed, 357 insertions, 15 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 @@ -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); @@ -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 */ @@ -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, |