diff options
Diffstat (limited to 'crypto/testmgr.c')
-rw-r--r-- | crypto/testmgr.c | 795 |
1 files changed, 343 insertions, 452 deletions
diff --git a/crypto/testmgr.c b/crypto/testmgr.c index 6a870e21b0cf..e5d8a0b8aea5 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -72,18 +72,6 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask) #define XBUFSIZE 8 /* - * Indexes into the xbuf to simulate cross-page access. - */ -#define IDX1 32 -#define IDX2 32400 -#define IDX3 1511 -#define IDX4 8193 -#define IDX5 22222 -#define IDX6 17101 -#define IDX7 27333 -#define IDX8 3000 - -/* * Used by test_cipher() */ #define ENCRYPT 1 @@ -149,9 +137,6 @@ struct alg_test_desc { } suite; }; -static const unsigned int IDX[8] = { - IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; - static void hexdump(unsigned char *buf, unsigned int len) { print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, @@ -346,6 +331,79 @@ static const struct testvec_config default_cipher_testvec_configs[] = { } }; +static const struct testvec_config default_hash_testvec_configs[] = { + { + .name = "init+update+final aligned buffer", + .src_divs = { { .proportion_of_total = 10000 } }, + .finalization_type = FINALIZATION_TYPE_FINAL, + }, { + .name = "init+finup aligned buffer", + .src_divs = { { .proportion_of_total = 10000 } }, + .finalization_type = FINALIZATION_TYPE_FINUP, + }, { + .name = "digest aligned buffer", + .src_divs = { { .proportion_of_total = 10000 } }, + .finalization_type = FINALIZATION_TYPE_DIGEST, + }, { + .name = "init+update+final misaligned buffer", + .src_divs = { { .proportion_of_total = 10000, .offset = 1 } }, + .finalization_type = FINALIZATION_TYPE_FINAL, + }, { + .name = "digest buffer aligned only to alignmask", + .src_divs = { + { + .proportion_of_total = 10000, + .offset = 1, + .offset_relative_to_alignmask = true, + }, + }, + .finalization_type = FINALIZATION_TYPE_DIGEST, + }, { + .name = "init+update+update+final two even splits", + .src_divs = { + { .proportion_of_total = 5000 }, + { + .proportion_of_total = 5000, + .flush_type = FLUSH_TYPE_FLUSH, + }, + }, + .finalization_type = FINALIZATION_TYPE_FINAL, + }, { + .name = "digest uneven misaligned splits, may sleep", + .req_flags = CRYPTO_TFM_REQ_MAY_SLEEP, + .src_divs = { + { .proportion_of_total = 1900, .offset = 33 }, + { .proportion_of_total = 3300, .offset = 7 }, + { .proportion_of_total = 4800, .offset = 18 }, + }, + .finalization_type = FINALIZATION_TYPE_DIGEST, + }, { + .name = "digest misaligned splits crossing pages", + .src_divs = { + { + .proportion_of_total = 7500, + .offset = PAGE_SIZE - 32, + }, { + .proportion_of_total = 2500, + .offset = PAGE_SIZE - 7, + }, + }, + .finalization_type = FINALIZATION_TYPE_DIGEST, + }, { + .name = "import/export", + .src_divs = { + { + .proportion_of_total = 6500, + .flush_type = FLUSH_TYPE_REIMPORT, + }, { + .proportion_of_total = 3500, + .flush_type = FLUSH_TYPE_REIMPORT, + }, + }, + .finalization_type = FINALIZATION_TYPE_FINAL, + } +}; + static unsigned int count_test_sg_divisions(const struct test_sg_division *divs) { unsigned int remaining = TEST_SG_TOTAL; @@ -782,430 +840,320 @@ static void generate_random_testvec_config(struct testvec_config *cfg, } #endif /* CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */ -static int ahash_guard_result(char *result, char c, int size) +static int check_nonfinal_hash_op(const char *op, int err, + u8 *result, unsigned int digestsize, + const char *driver, unsigned int vec_num, + const struct testvec_config *cfg) { - int i; - - for (i = 0; i < size; i++) { - if (result[i] != c) - return -EINVAL; - } - - return 0; -} - -static int ahash_partial_update(struct ahash_request **preq, - struct crypto_ahash *tfm, const struct hash_testvec *template, - void *hash_buff, int k, int temp, struct scatterlist *sg, - const char *algo, char *result, struct crypto_wait *wait) -{ - char *state; - struct ahash_request *req; - int statesize, ret = -EINVAL; - static const unsigned char guard[] = { 0x00, 0xba, 0xad, 0x00 }; - int digestsize = crypto_ahash_digestsize(tfm); - - req = *preq; - statesize = crypto_ahash_statesize( - crypto_ahash_reqtfm(req)); - state = kmalloc(statesize + sizeof(guard), GFP_KERNEL); - if (!state) { - pr_err("alg: hash: Failed to alloc state for %s\n", algo); - goto out_nostate; - } - memcpy(state + statesize, guard, sizeof(guard)); - memset(result, 1, digestsize); - ret = crypto_ahash_export(req, state); - WARN_ON(memcmp(state + statesize, guard, sizeof(guard))); - if (ret) { - pr_err("alg: hash: Failed to export() for %s\n", algo); - goto out; - } - ret = ahash_guard_result(result, 1, digestsize); - if (ret) { - pr_err("alg: hash: Failed, export used req->result for %s\n", - algo); - goto out; - } - ahash_request_free(req); - req = ahash_request_alloc(tfm, GFP_KERNEL); - if (!req) { - pr_err("alg: hash: Failed to alloc request for %s\n", algo); - goto out_noreq; - } - ahash_request_set_callback(req, - CRYPTO_TFM_REQ_MAY_BACKLOG, - crypto_req_done, wait); - - memcpy(hash_buff, template->plaintext + temp, - template->tap[k]); - sg_init_one(&sg[0], hash_buff, template->tap[k]); - ahash_request_set_crypt(req, sg, result, template->tap[k]); - ret = crypto_ahash_import(req, state); - if (ret) { - pr_err("alg: hash: Failed to import() for %s\n", algo); - goto out; + if (err) { + pr_err("alg: hash: %s %s() failed with err %d on test vector %u, cfg=\"%s\"\n", + driver, op, err, vec_num, cfg->name); + return err; } - ret = ahash_guard_result(result, 1, digestsize); - if (ret) { - pr_err("alg: hash: Failed, import used req->result for %s\n", - algo); - goto out; + if (!testmgr_is_poison(result, digestsize)) { + pr_err("alg: hash: %s %s() used result buffer on test vector %u, cfg=\"%s\"\n", + driver, op, vec_num, cfg->name); + return -EINVAL; } - ret = crypto_wait_req(crypto_ahash_update(req), wait); - if (ret) - goto out; - *preq = req; - ret = 0; - goto out_noreq; -out: - ahash_request_free(req); -out_noreq: - kfree(state); -out_nostate: - return ret; + return 0; } -enum hash_test { - HASH_TEST_DIGEST, - HASH_TEST_FINAL, - HASH_TEST_FINUP -}; - -static int __test_hash(struct crypto_ahash *tfm, - const struct hash_testvec *template, unsigned int tcount, - enum hash_test test_type, const int align_offset) +static int test_hash_vec_cfg(const char *driver, + const struct hash_testvec *vec, + unsigned int vec_num, + const struct testvec_config *cfg, + struct ahash_request *req, + struct test_sglist *tsgl, + u8 *hashstate) { - const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm)); - size_t digest_size = crypto_ahash_digestsize(tfm); - unsigned int i, j, k, temp; - struct scatterlist sg[8]; - char *result; - char *key; - struct ahash_request *req; - struct crypto_wait wait; - void *hash_buff; - char *xbuf[XBUFSIZE]; - int ret = -ENOMEM; - - result = kmalloc(digest_size, GFP_KERNEL); - if (!result) - return ret; - key = kmalloc(MAX_KEYLEN, GFP_KERNEL); - if (!key) - goto out_nobuf; - if (testmgr_alloc_buf(xbuf)) - goto out_nobuf; + struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); + const unsigned int alignmask = crypto_ahash_alignmask(tfm); + const unsigned int digestsize = crypto_ahash_digestsize(tfm); + const unsigned int statesize = crypto_ahash_statesize(tfm); + const u32 req_flags = CRYPTO_TFM_REQ_MAY_BACKLOG | cfg->req_flags; + const struct test_sg_division *divs[XBUFSIZE]; + DECLARE_CRYPTO_WAIT(wait); + struct kvec _input; + struct iov_iter input; + unsigned int i; + struct scatterlist *pending_sgl; + unsigned int pending_len; + u8 result[HASH_MAX_DIGESTSIZE + TESTMGR_POISON_LEN]; + int err; - crypto_init_wait(&wait); + /* Set the key, if specified */ + if (vec->ksize) { + err = crypto_ahash_setkey(tfm, vec->key, vec->ksize); + if (err) { + pr_err("alg: hash: %s setkey failed with err %d on test vector %u; flags=%#x\n", + driver, err, vec_num, + crypto_ahash_get_flags(tfm)); + return err; + } + } - req = ahash_request_alloc(tfm, GFP_KERNEL); - if (!req) { - printk(KERN_ERR "alg: hash: Failed to allocate request for " - "%s\n", algo); - goto out_noreq; + /* Build the scatterlist for the source data */ + _input.iov_base = (void *)vec->plaintext; + _input.iov_len = vec->psize; + iov_iter_kvec(&input, WRITE, &_input, 1, vec->psize); + err = build_test_sglist(tsgl, cfg->src_divs, alignmask, vec->psize, + &input, divs); + if (err) { + pr_err("alg: hash: %s: error preparing scatterlist for test vector %u, cfg=\"%s\"\n", + driver, vec_num, cfg->name); + return err; } - ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - crypto_req_done, &wait); - j = 0; - for (i = 0; i < tcount; i++) { - if (template[i].np) - continue; + /* Do the actual hashing */ - ret = -EINVAL; - if (WARN_ON(align_offset + template[i].psize > PAGE_SIZE)) - goto out; + testmgr_poison(req->__ctx, crypto_ahash_reqsize(tfm)); + testmgr_poison(result, digestsize + TESTMGR_POISON_LEN); - j++; - memset(result, 0, digest_size); + if (cfg->finalization_type == FINALIZATION_TYPE_DIGEST) { + /* Just using digest() */ + ahash_request_set_callback(req, req_flags, crypto_req_done, + &wait); + ahash_request_set_crypt(req, tsgl->sgl, result, vec->psize); + err = crypto_wait_req(crypto_ahash_digest(req), &wait); + if (err) { + pr_err("alg: hash: %s digest() failed with err %d on test vector %u, cfg=\"%s\"\n", + driver, err, vec_num, cfg->name); + return err; + } + goto result_ready; + } - hash_buff = xbuf[0]; - hash_buff += align_offset; + /* Using init(), zero or more update(), then final() or finup() */ - memcpy(hash_buff, template[i].plaintext, template[i].psize); - sg_init_one(&sg[0], hash_buff, template[i].psize); + ahash_request_set_callback(req, req_flags, crypto_req_done, &wait); + ahash_request_set_crypt(req, NULL, result, 0); + err = crypto_wait_req(crypto_ahash_init(req), &wait); + err = check_nonfinal_hash_op("init", err, result, digestsize, + driver, vec_num, cfg); + if (err) + return err; - if (template[i].ksize) { - crypto_ahash_clear_flags(tfm, ~0); - if (template[i].ksize > MAX_KEYLEN) { - pr_err("alg: hash: setkey failed on test %d for %s: key size %d > %d\n", - j, algo, template[i].ksize, MAX_KEYLEN); - ret = -EINVAL; - goto out; - } - memcpy(key, template[i].key, template[i].ksize); - ret = crypto_ahash_setkey(tfm, key, template[i].ksize); - if (ret) { - printk(KERN_ERR "alg: hash: setkey failed on " - "test %d for %s: ret=%d\n", j, algo, - -ret); - goto out; - } + pending_sgl = NULL; + pending_len = 0; + for (i = 0; i < tsgl->nents; i++) { + if (divs[i]->flush_type != FLUSH_TYPE_NONE && + pending_sgl != NULL) { + /* update() with the pending data */ + ahash_request_set_callback(req, req_flags, + crypto_req_done, &wait); + ahash_request_set_crypt(req, pending_sgl, result, + pending_len); + err = crypto_wait_req(crypto_ahash_update(req), &wait); + err = check_nonfinal_hash_op("update", err, + result, digestsize, + driver, vec_num, cfg); + if (err) + return err; + pending_sgl = NULL; + pending_len = 0; } - - ahash_request_set_crypt(req, sg, result, template[i].psize); - switch (test_type) { - case HASH_TEST_DIGEST: - ret = crypto_wait_req(crypto_ahash_digest(req), &wait); - if (ret) { - pr_err("alg: hash: digest failed on test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - break; - - case HASH_TEST_FINAL: - memset(result, 1, digest_size); - ret = crypto_wait_req(crypto_ahash_init(req), &wait); - if (ret) { - pr_err("alg: hash: init failed on test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - ret = ahash_guard_result(result, 1, digest_size); - if (ret) { - pr_err("alg: hash: init failed on test %d " - "for %s: used req->result\n", j, algo); - goto out; - } - ret = crypto_wait_req(crypto_ahash_update(req), &wait); - if (ret) { - pr_err("alg: hash: update failed on test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - ret = ahash_guard_result(result, 1, digest_size); - if (ret) { - pr_err("alg: hash: update failed on test %d " - "for %s: used req->result\n", j, algo); - goto out; - } - ret = crypto_wait_req(crypto_ahash_final(req), &wait); - if (ret) { - pr_err("alg: hash: final failed on test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; + if (divs[i]->flush_type == FLUSH_TYPE_REIMPORT) { + /* Test ->export() and ->import() */ + testmgr_poison(hashstate + statesize, + TESTMGR_POISON_LEN); + err = crypto_ahash_export(req, hashstate); + err = check_nonfinal_hash_op("export", err, + result, digestsize, + driver, vec_num, cfg); + if (err) + return err; + if (!testmgr_is_poison(hashstate + statesize, + TESTMGR_POISON_LEN)) { + pr_err("alg: hash: %s export() overran state buffer on test vector %u, cfg=\"%s\"\n", + driver, vec_num, cfg->name); + return -EOVERFLOW; } - break; - case HASH_TEST_FINUP: - memset(result, 1, digest_size); - ret = crypto_wait_req(crypto_ahash_init(req), &wait); - if (ret) { - pr_err("alg: hash: init failed on test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - ret = ahash_guard_result(result, 1, digest_size); - if (ret) { - pr_err("alg: hash: init failed on test %d " - "for %s: used req->result\n", j, algo); - goto out; - } - ret = crypto_wait_req(crypto_ahash_finup(req), &wait); - if (ret) { - pr_err("alg: hash: final failed on test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - break; + testmgr_poison(req->__ctx, crypto_ahash_reqsize(tfm)); + err = crypto_ahash_import(req, hashstate); + err = check_nonfinal_hash_op("import", err, + result, digestsize, + driver, vec_num, cfg); + if (err) + return err; } + if (pending_sgl == NULL) + pending_sgl = &tsgl->sgl[i]; + pending_len += tsgl->sgl[i].length; + } - if (memcmp(result, template[i].digest, - crypto_ahash_digestsize(tfm))) { - printk(KERN_ERR "alg: hash: Test %d failed for %s\n", - j, algo); - hexdump(result, crypto_ahash_digestsize(tfm)); - ret = -EINVAL; - goto out; + ahash_request_set_callback(req, req_flags, crypto_req_done, &wait); + ahash_request_set_crypt(req, pending_sgl, result, pending_len); + if (cfg->finalization_type == FINALIZATION_TYPE_FINAL) { + /* finish with update() and final() */ + err = crypto_wait_req(crypto_ahash_update(req), &wait); + err = check_nonfinal_hash_op("update", err, result, digestsize, + driver, vec_num, cfg); + if (err) + return err; + err = crypto_wait_req(crypto_ahash_final(req), &wait); + if (err) { + pr_err("alg: hash: %s final() failed with err %d on test vector %u, cfg=\"%s\"\n", + driver, err, vec_num, cfg->name); + return err; + } + } else { + /* finish with finup() */ + err = crypto_wait_req(crypto_ahash_finup(req), &wait); + if (err) { + pr_err("alg: hash: %s finup() failed with err %d on test vector %u, cfg=\"%s\"\n", + driver, err, vec_num, cfg->name); + return err; } } - if (test_type) - goto out; - - j = 0; - for (i = 0; i < tcount; i++) { - /* alignment tests are only done with continuous buffers */ - if (align_offset != 0) - break; +result_ready: + /* Check that the algorithm produced the correct digest */ + if (memcmp(result, vec->digest, digestsize) != 0) { + pr_err("alg: hash: %s test failed (wrong result) on test vector %u, cfg=\"%s\"\n", + driver, vec_num, cfg->name); + return -EINVAL; + } + if (!testmgr_is_poison(&result[digestsize], TESTMGR_POISON_LEN)) { + pr_err("alg: hash: %s overran result buffer on test vector %u, cfg=\"%s\"\n", + driver, vec_num, cfg->name); + return -EOVERFLOW; + } - if (!template[i].np) - continue; + return 0; +} - j++; - memset(result, 0, digest_size); +static int test_hash_vec(const char *driver, const struct hash_testvec *vec, + unsigned int vec_num, struct ahash_request *req, + struct test_sglist *tsgl, u8 *hashstate) +{ + unsigned int i; + int err; - temp = 0; - sg_init_table(sg, template[i].np); - ret = -EINVAL; - for (k = 0; k < template[i].np; k++) { - if (WARN_ON(offset_in_page(IDX[k]) + - template[i].tap[k] > PAGE_SIZE)) - goto out; - sg_set_buf(&sg[k], - memcpy(xbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]), - template[i].plaintext + temp, - template[i].tap[k]), - template[i].tap[k]); - temp += template[i].tap[k]; - } - - if (template[i].ksize) { - if (template[i].ksize > MAX_KEYLEN) { - pr_err("alg: hash: setkey failed on test %d for %s: key size %d > %d\n", - j, algo, template[i].ksize, MAX_KEYLEN); - ret = -EINVAL; - goto out; - } - crypto_ahash_clear_flags(tfm, ~0); - memcpy(key, template[i].key, template[i].ksize); - ret = crypto_ahash_setkey(tfm, key, template[i].ksize); - - if (ret) { - printk(KERN_ERR "alg: hash: setkey " - "failed on chunking test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - } + for (i = 0; i < ARRAY_SIZE(default_hash_testvec_configs); i++) { + err = test_hash_vec_cfg(driver, vec, vec_num, + &default_hash_testvec_configs[i], + req, tsgl, hashstate); + if (err) + return err; + } - ahash_request_set_crypt(req, sg, result, template[i].psize); - ret = crypto_wait_req(crypto_ahash_digest(req), &wait); - if (ret) { - pr_err("alg: hash: digest failed on chunking test %d for %s: ret=%d\n", - j, algo, -ret); - goto out; - } +#ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS + if (!noextratests) { + struct testvec_config cfg; + char cfgname[TESTVEC_CONFIG_NAMELEN]; - if (memcmp(result, template[i].digest, - crypto_ahash_digestsize(tfm))) { - printk(KERN_ERR "alg: hash: Chunking test %d " - "failed for %s\n", j, algo); - hexdump(result, crypto_ahash_digestsize(tfm)); - ret = -EINVAL; - goto out; + for (i = 0; i < fuzz_iterations; i++) { + generate_random_testvec_config(&cfg, cfgname, + sizeof(cfgname)); + err = test_hash_vec_cfg(driver, vec, vec_num, &cfg, + req, tsgl, hashstate); + if (err) + return err; } } +#endif + return 0; +} - /* partial update exercise */ - j = 0; - for (i = 0; i < tcount; i++) { - /* alignment tests are only done with continuous buffers */ - if (align_offset != 0) - break; +static int __alg_test_hash(const struct hash_testvec *vecs, + unsigned int num_vecs, const char *driver, + u32 type, u32 mask) +{ + struct crypto_ahash *tfm; + struct ahash_request *req = NULL; + struct test_sglist *tsgl = NULL; + u8 *hashstate = NULL; + unsigned int i; + int err; - if (template[i].np < 2) - continue; + tfm = crypto_alloc_ahash(driver, type, mask); + if (IS_ERR(tfm)) { + pr_err("alg: hash: failed to allocate transform for %s: %ld\n", + driver, PTR_ERR(tfm)); + return PTR_ERR(tfm); + } - j++; - memset(result, 0, digest_size); + req = ahash_request_alloc(tfm, GFP_KERNEL); + if (!req) { + pr_err("alg: hash: failed to allocate request for %s\n", + driver); + err = -ENOMEM; + goto out; + } - ret = -EINVAL; - hash_buff = xbuf[0]; - memcpy(hash_buff, template[i].plaintext, - template[i].tap[0]); - sg_init_one(&sg[0], hash_buff, template[i].tap[0]); - - if (template[i].ksize) { - crypto_ahash_clear_flags(tfm, ~0); - if (template[i].ksize > MAX_KEYLEN) { - pr_err("alg: hash: setkey failed on test %d for %s: key size %d > %d\n", - j, algo, template[i].ksize, MAX_KEYLEN); - ret = -EINVAL; - goto out; - } - memcpy(key, template[i].key, template[i].ksize); - ret = crypto_ahash_setkey(tfm, key, template[i].ksize); - if (ret) { - pr_err("alg: hash: setkey failed on test %d for %s: ret=%d\n", - j, algo, -ret); - goto out; - } - } + tsgl = kmalloc(sizeof(*tsgl), GFP_KERNEL); + if (!tsgl || init_test_sglist(tsgl) != 0) { + pr_err("alg: hash: failed to allocate test buffers for %s\n", + driver); + kfree(tsgl); + tsgl = NULL; + err = -ENOMEM; + goto out; + } - ahash_request_set_crypt(req, sg, result, template[i].tap[0]); - ret = crypto_wait_req(crypto_ahash_init(req), &wait); - if (ret) { - pr_err("alg: hash: init failed on test %d for %s: ret=%d\n", - j, algo, -ret); - goto out; - } - ret = crypto_wait_req(crypto_ahash_update(req), &wait); - if (ret) { - pr_err("alg: hash: update failed on test %d for %s: ret=%d\n", - j, algo, -ret); - goto out; - } + hashstate = kmalloc(crypto_ahash_statesize(tfm) + TESTMGR_POISON_LEN, + GFP_KERNEL); + if (!hashstate) { + pr_err("alg: hash: failed to allocate hash state buffer for %s\n", + driver); + err = -ENOMEM; + goto out; + } - temp = template[i].tap[0]; - for (k = 1; k < template[i].np; k++) { - ret = ahash_partial_update(&req, tfm, &template[i], - hash_buff, k, temp, &sg[0], algo, result, - &wait); - if (ret) { - pr_err("alg: hash: partial update failed on test %d for %s: ret=%d\n", - j, algo, -ret); - goto out_noreq; - } - temp += template[i].tap[k]; - } - ret = crypto_wait_req(crypto_ahash_final(req), &wait); - if (ret) { - pr_err("alg: hash: final failed on test %d for %s: ret=%d\n", - j, algo, -ret); - goto out; - } - if (memcmp(result, template[i].digest, - crypto_ahash_digestsize(tfm))) { - pr_err("alg: hash: Partial Test %d failed for %s\n", - j, algo); - hexdump(result, crypto_ahash_digestsize(tfm)); - ret = -EINVAL; + for (i = 0; i < num_vecs; i++) { + err = test_hash_vec(driver, &vecs[i], i, req, tsgl, hashstate); + if (err) goto out; - } } - - ret = 0; - + err = 0; out: + kfree(hashstate); + if (tsgl) { + destroy_test_sglist(tsgl); + kfree(tsgl); + } ahash_request_free(req); -out_noreq: - testmgr_free_buf(xbuf); -out_nobuf: - kfree(key); - kfree(result); - return ret; + crypto_free_ahash(tfm); + return err; } -static int test_hash(struct crypto_ahash *tfm, - const struct hash_testvec *template, - unsigned int tcount, enum hash_test test_type) +static int alg_test_hash(const struct alg_test_desc *desc, const char *driver, + u32 type, u32 mask) { - unsigned int alignmask; - int ret; + const struct hash_testvec *template = desc->suite.hash.vecs; + unsigned int tcount = desc->suite.hash.count; + unsigned int nr_unkeyed, nr_keyed; + int err; - ret = __test_hash(tfm, template, tcount, test_type, 0); - if (ret) - return ret; + /* + * For OPTIONAL_KEY algorithms, we have to do all the unkeyed tests + * first, before setting a key on the tfm. To make this easier, we + * require that the unkeyed test vectors (if any) are listed first. + */ - /* test unaligned buffers, check with one byte offset */ - ret = __test_hash(tfm, template, tcount, test_type, 1); - if (ret) - return ret; + for (nr_unkeyed = 0; nr_unkeyed < tcount; nr_unkeyed++) { + if (template[nr_unkeyed].ksize) + break; + } + for (nr_keyed = 0; nr_unkeyed + nr_keyed < tcount; nr_keyed++) { + if (!template[nr_unkeyed + nr_keyed].ksize) { + pr_err("alg: hash: test vectors for %s out of order, " + "unkeyed ones must come first\n", desc->alg); + return -EINVAL; + } + } - alignmask = crypto_tfm_alg_alignmask(&tfm->base); - if (alignmask) { - /* Check if alignment mask for tfm is correctly set. */ - ret = __test_hash(tfm, template, tcount, test_type, - alignmask + 1); - if (ret) - return ret; + err = 0; + if (nr_unkeyed) { + err = __alg_test_hash(template, nr_unkeyed, driver, type, mask); + template += nr_unkeyed; } - return 0; + if (!err && nr_keyed) + err = __alg_test_hash(template, nr_keyed, driver, type, mask); + + return err; } static int test_aead_vec_cfg(const char *driver, int enc, @@ -2113,67 +2061,6 @@ static int alg_test_comp(const struct alg_test_desc *desc, const char *driver, return err; } -static int __alg_test_hash(const struct hash_testvec *template, - unsigned int tcount, const char *driver, - u32 type, u32 mask) -{ - struct crypto_ahash *tfm; - int err; - - tfm = crypto_alloc_ahash(driver, type, mask); - if (IS_ERR(tfm)) { - printk(KERN_ERR "alg: hash: Failed to load transform for %s: " - "%ld\n", driver, PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - - err = test_hash(tfm, template, tcount, HASH_TEST_DIGEST); - if (!err) - err = test_hash(tfm, template, tcount, HASH_TEST_FINAL); - if (!err) - err = test_hash(tfm, template, tcount, HASH_TEST_FINUP); - crypto_free_ahash(tfm); - return err; -} - -static int alg_test_hash(const struct alg_test_desc *desc, const char *driver, - u32 type, u32 mask) -{ - const struct hash_testvec *template = desc->suite.hash.vecs; - unsigned int tcount = desc->suite.hash.count; - unsigned int nr_unkeyed, nr_keyed; - int err; - - /* - * For OPTIONAL_KEY algorithms, we have to do all the unkeyed tests - * first, before setting a key on the tfm. To make this easier, we - * require that the unkeyed test vectors (if any) are listed first. - */ - - for (nr_unkeyed = 0; nr_unkeyed < tcount; nr_unkeyed++) { - if (template[nr_unkeyed].ksize) - break; - } - for (nr_keyed = 0; nr_unkeyed + nr_keyed < tcount; nr_keyed++) { - if (!template[nr_unkeyed + nr_keyed].ksize) { - pr_err("alg: hash: test vectors for %s out of order, " - "unkeyed ones must come first\n", desc->alg); - return -EINVAL; - } - } - - err = 0; - if (nr_unkeyed) { - err = __alg_test_hash(template, nr_unkeyed, driver, type, mask); - template += nr_unkeyed; - } - - if (!err && nr_keyed) - err = __alg_test_hash(template, nr_keyed, driver, type, mask); - - return err; -} - static int alg_test_crc32c(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask) { @@ -3956,6 +3843,10 @@ static void alg_check_testvec_configs(void) for (i = 0; i < ARRAY_SIZE(default_cipher_testvec_configs); i++) WARN_ON(!valid_testvec_config( &default_cipher_testvec_configs[i])); + + for (i = 0; i < ARRAY_SIZE(default_hash_testvec_configs); i++) + WARN_ON(!valid_testvec_config( + &default_hash_testvec_configs[i])); } static void testmgr_onetime_init(void) |