From 9de348f24de5ab4f6eafba7a20f3fa64912b917b Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Wed, 25 Aug 2010 01:05:43 +0200 Subject: Define session cloning interface --- crypto.4 | 5 +++++ ncr.h | 1 + utils.c | 1 + 3 files changed, 7 insertions(+) diff --git a/crypto.4 b/crypto.4 index 0dc21e9..04d952e 100644 --- a/crypto.4 +++ b/crypto.4 @@ -543,6 +543,11 @@ 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; +specifically intended for cloning hashing sessions. .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/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, -- cgit From db7c441175942d3b3c3e6321a9a16dc7e83b747c Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Wed, 25 Aug 2010 04:31:52 +0200 Subject: Remove a redundant argument of cryptodev_hash_init --- cryptodev_cipher.c | 4 ++-- cryptodev_int.h | 2 +- libtomcrypt/hashes/hash_memory.c | 2 +- libtomcrypt/hashes/hash_memory_multi.c | 2 +- ncr-sessions.c | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cryptodev_cipher.c b/cryptodev_cipher.c index 4e74fcc..dae4a63 100644 --- a/cryptodev_cipher.c +++ b/cryptodev_cipher.c @@ -216,7 +216,7 @@ ssize_t cryptodev_cipher_decrypt( struct cipher_data* cdata, const struct scatte /* Hash functions */ -int cryptodev_hash_init( struct hash_data* hdata, const char* alg_name, int hmac_mode, void * mackey, size_t mackeylen) +int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name, const void *mackey, size_t mackeylen) { int ret; @@ -228,7 +228,7 @@ int ret; } /* Copy the key from user and set to TFM. */ - if (hmac_mode != 0) { + if (mackey != NULL) { ret = crypto_ahash_setkey(hdata->async.s, mackey, mackeylen); if (unlikely(ret)) { diff --git a/cryptodev_int.h b/cryptodev_int.h index e381505..573fcaa 100644 --- a/cryptodev_int.h +++ b/cryptodev_int.h @@ -77,6 +77,6 @@ ssize_t cryptodev_hash_update( struct hash_data* hdata, struct scatterlist *sg, ssize_t _cryptodev_hash_update( struct hash_data* hdata, const void* data, size_t len); 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, int hmac_mode, void* mackey, size_t mackeylen); +int cryptodev_hash_init(struct hash_data *hdata, const char *alg_name, const void *mackey, size_t mackeylen); #endif /* CRYPTODEV_INT_H */ diff --git a/libtomcrypt/hashes/hash_memory.c b/libtomcrypt/hashes/hash_memory.c index a416de9..c6f5188 100644 --- a/libtomcrypt/hashes/hash_memory.c +++ b/libtomcrypt/hashes/hash_memory.c @@ -44,7 +44,7 @@ int hash_memory(const struct algo_properties_st *hash, const unsigned char *in, return CRYPT_BUFFER_OVERFLOW; } - err = cryptodev_hash_init( &hdata, hash->kstr, 0, NULL, 0); + err = cryptodev_hash_init(&hdata, hash->kstr, NULL, 0); if (err < 0) { err = CRYPT_INVALID_HASH; goto LBL_ERR; diff --git a/libtomcrypt/hashes/hash_memory_multi.c b/libtomcrypt/hashes/hash_memory_multi.c index a914916..7422676 100644 --- a/libtomcrypt/hashes/hash_memory_multi.c +++ b/libtomcrypt/hashes/hash_memory_multi.c @@ -50,7 +50,7 @@ int hash_memory_multi(const struct algo_properties_st *hash, unsigned char *out, return CRYPT_BUFFER_OVERFLOW; } - err = cryptodev_hash_init( &hdata, hash->kstr, 0, NULL, 0); + err = cryptodev_hash_init(&hdata, hash->kstr, NULL, 0); if (err < 0) { err = CRYPT_INVALID_HASH; goto LBL_ERR; diff --git a/ncr-sessions.c b/ncr-sessions.c index 2521f2e..a08f237 100644 --- a/ncr-sessions.c +++ b/ncr-sessions.c @@ -444,7 +444,7 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists, goto fail; } - ret = cryptodev_hash_init(&ns->hash, ns->algorithm->kstr, 0, NULL, 0); + ret = cryptodev_hash_init(&ns->hash, ns->algorithm->kstr, NULL, 0); if (ret < 0) { err(); goto fail; @@ -474,7 +474,7 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists, goto fail; } - ret = cryptodev_hash_init(&ns->hash, ns->algorithm->kstr, 1, + ret = cryptodev_hash_init(&ns->hash, ns->algorithm->kstr, ns->key->key.secret.data, ns->key->key.secret.size); if (ret < 0) { err(); @@ -509,7 +509,7 @@ static struct session_item_st *_ncr_session_init(struct ncr_lists *lists, goto fail; } - ret = cryptodev_hash_init(&ns->hash, sign_hash->kstr, 0, NULL, 0); + ret = cryptodev_hash_init(&ns->hash, sign_hash->kstr, NULL, 0); if (ret < 0) { err(); goto fail; -- cgit From 56895fcb6ada286ee95df0e49076f2785c45a0db Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Wed, 25 Aug 2010 05:20:11 +0200 Subject: Implement cloning hash sessions --- crypto.4 | 10 ++++-- cryptodev_cipher.c | 42 +++++++++++++++++++++++ cryptodev_int.h | 2 ++ ncr-sessions.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++-------- 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); -- cgit From 5d586cad2979ad279e9a7f0985d008e5d649bbc5 Mon Sep 17 00:00:00 2001 From: Miloslav Trmač Date: Wed, 25 Aug 2010 05:46:06 +0200 Subject: Add hash cloning example. --- examples/ncr.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 218 insertions(+) diff --git a/examples/ncr.c b/examples/ncr.c index a7d34f0..2039516 100644 --- a/examples/ncr.c +++ b/examples/ncr.c @@ -1236,6 +1236,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) { @@ -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; -- cgit