summaryrefslogtreecommitdiffstats
path: root/crypto/testmgr.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-07-08 20:57:08 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-07-08 20:57:08 -0700
commit4d2fa8b44b891f0da5ceda3e5a1402ccf0ab6f26 (patch)
treecbb763ec5e74cfbaac6ce53df277883cb78a8a1a /crypto/testmgr.c
parent8b68150883ca466a23e90902dd4113b22e692f04 (diff)
parentf3880a23564e3172437285ebcb5b8a124539fdae (diff)
downloadlinux-4d2fa8b44b891f0da5ceda3e5a1402ccf0ab6f26.tar.bz2
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
Pull crypto updates from Herbert Xu: "Here is the crypto update for 5.3: API: - Test shash interface directly in testmgr - cra_driver_name is now mandatory Algorithms: - Replace arc4 crypto_cipher with library helper - Implement 5 way interleave for ECB, CBC and CTR on arm64 - Add xxhash - Add continuous self-test on noise source to drbg - Update jitter RNG Drivers: - Add support for SHA204A random number generator - Add support for 7211 in iproc-rng200 - Fix fuzz test failures in inside-secure - Fix fuzz test failures in talitos - Fix fuzz test failures in qat" * 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6: (143 commits) crypto: stm32/hash - remove interruptible condition for dma crypto: stm32/hash - Fix hmac issue more than 256 bytes crypto: stm32/crc32 - rename driver file crypto: amcc - remove memset after dma_alloc_coherent crypto: ccp - Switch to SPDX license identifiers crypto: ccp - Validate the the error value used to index error messages crypto: doc - Fix formatting of new crypto engine content crypto: doc - Add parameter documentation crypto: arm64/aes-ce - implement 5 way interleave for ECB, CBC and CTR crypto: arm64/aes-ce - add 5 way interleave routines crypto: talitos - drop icv_ool crypto: talitos - fix hash on SEC1. crypto: talitos - move struct talitos_edesc into talitos.h lib/scatterlist: Fix mapping iterator when sg->offset is greater than PAGE_SIZE crypto/NX: Set receive window credits to max number of CRBs in RxFIFO crypto: asymmetric_keys - select CRYPTO_HASH where needed crypto: serpent - mark __serpent_setkey_sbox noinline crypto: testmgr - dynamically allocate crypto_shash crypto: testmgr - dynamically allocate testvec_config crypto: talitos - eliminate unneeded 'done' functions at build time ...
Diffstat (limited to 'crypto/testmgr.c')
-rw-r--r--crypto/testmgr.c478
1 files changed, 394 insertions, 84 deletions
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 658a7eeebab2..d0b5b33806a6 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -1032,6 +1032,205 @@ static void crypto_reenable_simd_for_test(void)
}
#endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
+static int build_hash_sglist(struct test_sglist *tsgl,
+ const struct hash_testvec *vec,
+ const struct testvec_config *cfg,
+ unsigned int alignmask,
+ const struct test_sg_division *divs[XBUFSIZE])
+{
+ struct kvec kv;
+ struct iov_iter input;
+
+ kv.iov_base = (void *)vec->plaintext;
+ kv.iov_len = vec->psize;
+ iov_iter_kvec(&input, WRITE, &kv, 1, vec->psize);
+ return build_test_sglist(tsgl, cfg->src_divs, alignmask, vec->psize,
+ &input, divs);
+}
+
+static int check_hash_result(const char *type,
+ const u8 *result, unsigned int digestsize,
+ const struct hash_testvec *vec,
+ const char *vec_name,
+ const char *driver,
+ const struct testvec_config *cfg)
+{
+ if (memcmp(result, vec->digest, digestsize) != 0) {
+ pr_err("alg: %s: %s test failed (wrong result) on test vector %s, cfg=\"%s\"\n",
+ type, driver, vec_name, cfg->name);
+ return -EINVAL;
+ }
+ if (!testmgr_is_poison(&result[digestsize], TESTMGR_POISON_LEN)) {
+ pr_err("alg: %s: %s overran result buffer on test vector %s, cfg=\"%s\"\n",
+ type, driver, vec_name, cfg->name);
+ return -EOVERFLOW;
+ }
+ return 0;
+}
+
+static inline int check_shash_op(const char *op, int err,
+ const char *driver, const char *vec_name,
+ const struct testvec_config *cfg)
+{
+ if (err)
+ pr_err("alg: shash: %s %s() failed with err %d on test vector %s, cfg=\"%s\"\n",
+ driver, op, err, vec_name, cfg->name);
+ return err;
+}
+
+static inline const void *sg_data(struct scatterlist *sg)
+{
+ return page_address(sg_page(sg)) + sg->offset;
+}
+
+/* Test one hash test vector in one configuration, using the shash API */
+static int test_shash_vec_cfg(const char *driver,
+ const struct hash_testvec *vec,
+ const char *vec_name,
+ const struct testvec_config *cfg,
+ struct shash_desc *desc,
+ struct test_sglist *tsgl,
+ u8 *hashstate)
+{
+ struct crypto_shash *tfm = desc->tfm;
+ const unsigned int alignmask = crypto_shash_alignmask(tfm);
+ const unsigned int digestsize = crypto_shash_digestsize(tfm);
+ const unsigned int statesize = crypto_shash_statesize(tfm);
+ const struct test_sg_division *divs[XBUFSIZE];
+ unsigned int i;
+ u8 result[HASH_MAX_DIGESTSIZE + TESTMGR_POISON_LEN];
+ int err;
+
+ /* Set the key, if specified */
+ if (vec->ksize) {
+ err = crypto_shash_setkey(tfm, vec->key, vec->ksize);
+ if (err) {
+ if (err == vec->setkey_error)
+ return 0;
+ pr_err("alg: shash: %s setkey failed on test vector %s; expected_error=%d, actual_error=%d, flags=%#x\n",
+ driver, vec_name, vec->setkey_error, err,
+ crypto_shash_get_flags(tfm));
+ return err;
+ }
+ if (vec->setkey_error) {
+ pr_err("alg: shash: %s setkey unexpectedly succeeded on test vector %s; expected_error=%d\n",
+ driver, vec_name, vec->setkey_error);
+ return -EINVAL;
+ }
+ }
+
+ /* Build the scatterlist for the source data */
+ err = build_hash_sglist(tsgl, vec, cfg, alignmask, divs);
+ if (err) {
+ pr_err("alg: shash: %s: error preparing scatterlist for test vector %s, cfg=\"%s\"\n",
+ driver, vec_name, cfg->name);
+ return err;
+ }
+
+ /* Do the actual hashing */
+
+ testmgr_poison(desc->__ctx, crypto_shash_descsize(tfm));
+ testmgr_poison(result, digestsize + TESTMGR_POISON_LEN);
+
+ if (cfg->finalization_type == FINALIZATION_TYPE_DIGEST ||
+ vec->digest_error) {
+ /* Just using digest() */
+ if (tsgl->nents != 1)
+ return 0;
+ if (cfg->nosimd)
+ crypto_disable_simd_for_test();
+ err = crypto_shash_digest(desc, sg_data(&tsgl->sgl[0]),
+ tsgl->sgl[0].length, result);
+ if (cfg->nosimd)
+ crypto_reenable_simd_for_test();
+ if (err) {
+ if (err == vec->digest_error)
+ return 0;
+ pr_err("alg: shash: %s digest() failed on test vector %s; expected_error=%d, actual_error=%d, cfg=\"%s\"\n",
+ driver, vec_name, vec->digest_error, err,
+ cfg->name);
+ return err;
+ }
+ if (vec->digest_error) {
+ pr_err("alg: shash: %s digest() unexpectedly succeeded on test vector %s; expected_error=%d, cfg=\"%s\"\n",
+ driver, vec_name, vec->digest_error, cfg->name);
+ return -EINVAL;
+ }
+ goto result_ready;
+ }
+
+ /* Using init(), zero or more update(), then final() or finup() */
+
+ if (cfg->nosimd)
+ crypto_disable_simd_for_test();
+ err = crypto_shash_init(desc);
+ if (cfg->nosimd)
+ crypto_reenable_simd_for_test();
+ err = check_shash_op("init", err, driver, vec_name, cfg);
+ if (err)
+ return err;
+
+ for (i = 0; i < tsgl->nents; i++) {
+ if (i + 1 == tsgl->nents &&
+ cfg->finalization_type == FINALIZATION_TYPE_FINUP) {
+ if (divs[i]->nosimd)
+ crypto_disable_simd_for_test();
+ err = crypto_shash_finup(desc, sg_data(&tsgl->sgl[i]),
+ tsgl->sgl[i].length, result);
+ if (divs[i]->nosimd)
+ crypto_reenable_simd_for_test();
+ err = check_shash_op("finup", err, driver, vec_name,
+ cfg);
+ if (err)
+ return err;
+ goto result_ready;
+ }
+ if (divs[i]->nosimd)
+ crypto_disable_simd_for_test();
+ err = crypto_shash_update(desc, sg_data(&tsgl->sgl[i]),
+ tsgl->sgl[i].length);
+ if (divs[i]->nosimd)
+ crypto_reenable_simd_for_test();
+ err = check_shash_op("update", err, driver, vec_name, cfg);
+ if (err)
+ return err;
+ if (divs[i]->flush_type == FLUSH_TYPE_REIMPORT) {
+ /* Test ->export() and ->import() */
+ testmgr_poison(hashstate + statesize,
+ TESTMGR_POISON_LEN);
+ err = crypto_shash_export(desc, hashstate);
+ err = check_shash_op("export", err, driver, vec_name,
+ cfg);
+ if (err)
+ return err;
+ if (!testmgr_is_poison(hashstate + statesize,
+ TESTMGR_POISON_LEN)) {
+ pr_err("alg: shash: %s export() overran state buffer on test vector %s, cfg=\"%s\"\n",
+ driver, vec_name, cfg->name);
+ return -EOVERFLOW;
+ }
+ testmgr_poison(desc->__ctx, crypto_shash_descsize(tfm));
+ err = crypto_shash_import(desc, hashstate);
+ err = check_shash_op("import", err, driver, vec_name,
+ cfg);
+ if (err)
+ return err;
+ }
+ }
+
+ if (cfg->nosimd)
+ crypto_disable_simd_for_test();
+ err = crypto_shash_final(desc, result);
+ if (cfg->nosimd)
+ crypto_reenable_simd_for_test();
+ err = check_shash_op("final", err, driver, vec_name, cfg);
+ if (err)
+ return err;
+result_ready:
+ return check_hash_result("shash", result, digestsize, vec, vec_name,
+ driver, cfg);
+}
+
static int do_ahash_op(int (*op)(struct ahash_request *req),
struct ahash_request *req,
struct crypto_wait *wait, bool nosimd)
@@ -1049,31 +1248,32 @@ static int do_ahash_op(int (*op)(struct ahash_request *req),
return crypto_wait_req(err, wait);
}
-static int check_nonfinal_hash_op(const char *op, int err,
- u8 *result, unsigned int digestsize,
- const char *driver, const char *vec_name,
- const struct testvec_config *cfg)
+static int check_nonfinal_ahash_op(const char *op, int err,
+ u8 *result, unsigned int digestsize,
+ const char *driver, const char *vec_name,
+ const struct testvec_config *cfg)
{
if (err) {
- pr_err("alg: hash: %s %s() failed with err %d on test vector %s, cfg=\"%s\"\n",
+ pr_err("alg: ahash: %s %s() failed with err %d on test vector %s, cfg=\"%s\"\n",
driver, op, err, vec_name, cfg->name);
return err;
}
if (!testmgr_is_poison(result, digestsize)) {
- pr_err("alg: hash: %s %s() used result buffer on test vector %s, cfg=\"%s\"\n",
+ pr_err("alg: ahash: %s %s() used result buffer on test vector %s, cfg=\"%s\"\n",
driver, op, vec_name, cfg->name);
return -EINVAL;
}
return 0;
}
-static int test_hash_vec_cfg(const char *driver,
- const struct hash_testvec *vec,
- const char *vec_name,
- const struct testvec_config *cfg,
- struct ahash_request *req,
- struct test_sglist *tsgl,
- u8 *hashstate)
+/* Test one hash test vector in one configuration, using the ahash API */
+static int test_ahash_vec_cfg(const char *driver,
+ const struct hash_testvec *vec,
+ const char *vec_name,
+ const struct testvec_config *cfg,
+ struct ahash_request *req,
+ struct test_sglist *tsgl,
+ u8 *hashstate)
{
struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
const unsigned int alignmask = crypto_ahash_alignmask(tfm);
@@ -1082,8 +1282,6 @@ static int test_hash_vec_cfg(const char *driver,
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;
@@ -1096,26 +1294,22 @@ static int test_hash_vec_cfg(const char *driver,
if (err) {
if (err == vec->setkey_error)
return 0;
- pr_err("alg: hash: %s setkey failed on test vector %s; expected_error=%d, actual_error=%d, flags=%#x\n",
+ pr_err("alg: ahash: %s setkey failed on test vector %s; expected_error=%d, actual_error=%d, flags=%#x\n",
driver, vec_name, vec->setkey_error, err,
crypto_ahash_get_flags(tfm));
return err;
}
if (vec->setkey_error) {
- pr_err("alg: hash: %s setkey unexpectedly succeeded on test vector %s; expected_error=%d\n",
+ pr_err("alg: ahash: %s setkey unexpectedly succeeded on test vector %s; expected_error=%d\n",
driver, vec_name, vec->setkey_error);
return -EINVAL;
}
}
/* 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);
+ err = build_hash_sglist(tsgl, vec, cfg, alignmask, divs);
if (err) {
- pr_err("alg: hash: %s: error preparing scatterlist for test vector %s, cfg=\"%s\"\n",
+ pr_err("alg: ahash: %s: error preparing scatterlist for test vector %s, cfg=\"%s\"\n",
driver, vec_name, cfg->name);
return err;
}
@@ -1135,13 +1329,13 @@ static int test_hash_vec_cfg(const char *driver,
if (err) {
if (err == vec->digest_error)
return 0;
- pr_err("alg: hash: %s digest() failed on test vector %s; expected_error=%d, actual_error=%d, cfg=\"%s\"\n",
+ pr_err("alg: ahash: %s digest() failed on test vector %s; expected_error=%d, actual_error=%d, cfg=\"%s\"\n",
driver, vec_name, vec->digest_error, err,
cfg->name);
return err;
}
if (vec->digest_error) {
- pr_err("alg: hash: %s digest() unexpectedly succeeded on test vector %s; expected_error=%d, cfg=\"%s\"\n",
+ pr_err("alg: ahash: %s digest() unexpectedly succeeded on test vector %s; expected_error=%d, cfg=\"%s\"\n",
driver, vec_name, vec->digest_error, cfg->name);
return -EINVAL;
}
@@ -1153,8 +1347,8 @@ static int test_hash_vec_cfg(const char *driver,
ahash_request_set_callback(req, req_flags, crypto_req_done, &wait);
ahash_request_set_crypt(req, NULL, result, 0);
err = do_ahash_op(crypto_ahash_init, req, &wait, cfg->nosimd);
- err = check_nonfinal_hash_op("init", err, result, digestsize,
- driver, vec_name, cfg);
+ err = check_nonfinal_ahash_op("init", err, result, digestsize,
+ driver, vec_name, cfg);
if (err)
return err;
@@ -1170,9 +1364,9 @@ static int test_hash_vec_cfg(const char *driver,
pending_len);
err = do_ahash_op(crypto_ahash_update, req, &wait,
divs[i]->nosimd);
- err = check_nonfinal_hash_op("update", err,
- result, digestsize,
- driver, vec_name, cfg);
+ err = check_nonfinal_ahash_op("update", err,
+ result, digestsize,
+ driver, vec_name, cfg);
if (err)
return err;
pending_sgl = NULL;
@@ -1183,23 +1377,23 @@ static int test_hash_vec_cfg(const char *driver,
testmgr_poison(hashstate + statesize,
TESTMGR_POISON_LEN);
err = crypto_ahash_export(req, hashstate);
- err = check_nonfinal_hash_op("export", err,
- result, digestsize,
- driver, vec_name, cfg);
+ err = check_nonfinal_ahash_op("export", err,
+ result, digestsize,
+ driver, vec_name, 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 %s, cfg=\"%s\"\n",
+ pr_err("alg: ahash: %s export() overran state buffer on test vector %s, cfg=\"%s\"\n",
driver, vec_name, cfg->name);
return -EOVERFLOW;
}
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_name, cfg);
+ err = check_nonfinal_ahash_op("import", err,
+ result, digestsize,
+ driver, vec_name, cfg);
if (err)
return err;
}
@@ -1213,13 +1407,13 @@ static int test_hash_vec_cfg(const char *driver,
if (cfg->finalization_type == FINALIZATION_TYPE_FINAL) {
/* finish with update() and final() */
err = do_ahash_op(crypto_ahash_update, req, &wait, cfg->nosimd);
- err = check_nonfinal_hash_op("update", err, result, digestsize,
- driver, vec_name, cfg);
+ err = check_nonfinal_ahash_op("update", err, result, digestsize,
+ driver, vec_name, cfg);
if (err)
return err;
err = do_ahash_op(crypto_ahash_final, req, &wait, cfg->nosimd);
if (err) {
- pr_err("alg: hash: %s final() failed with err %d on test vector %s, cfg=\"%s\"\n",
+ pr_err("alg: ahash: %s final() failed with err %d on test vector %s, cfg=\"%s\"\n",
driver, err, vec_name, cfg->name);
return err;
}
@@ -1227,31 +1421,49 @@ static int test_hash_vec_cfg(const char *driver,
/* finish with finup() */
err = do_ahash_op(crypto_ahash_finup, req, &wait, cfg->nosimd);
if (err) {
- pr_err("alg: hash: %s finup() failed with err %d on test vector %s, cfg=\"%s\"\n",
+ pr_err("alg: ahash: %s finup() failed with err %d on test vector %s, cfg=\"%s\"\n",
driver, err, vec_name, cfg->name);
return err;
}
}
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 %s, cfg=\"%s\"\n",
- driver, vec_name, cfg->name);
- return -EINVAL;
- }
- if (!testmgr_is_poison(&result[digestsize], TESTMGR_POISON_LEN)) {
- pr_err("alg: hash: %s overran result buffer on test vector %s, cfg=\"%s\"\n",
- driver, vec_name, cfg->name);
- return -EOVERFLOW;
+ return check_hash_result("ahash", result, digestsize, vec, vec_name,
+ driver, cfg);
+}
+
+static int test_hash_vec_cfg(const char *driver,
+ const struct hash_testvec *vec,
+ const char *vec_name,
+ const struct testvec_config *cfg,
+ struct ahash_request *req,
+ struct shash_desc *desc,
+ struct test_sglist *tsgl,
+ u8 *hashstate)
+{
+ int err;
+
+ /*
+ * For algorithms implemented as "shash", most bugs will be detected by
+ * both the shash and ahash tests. Test the shash API first so that the
+ * failures involve less indirection, so are easier to debug.
+ */
+
+ if (desc) {
+ err = test_shash_vec_cfg(driver, vec, vec_name, cfg, desc, tsgl,
+ hashstate);
+ if (err)
+ return err;
}
- return 0;
+ return test_ahash_vec_cfg(driver, vec, vec_name, cfg, req, tsgl,
+ hashstate);
}
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)
+ struct shash_desc *desc, struct test_sglist *tsgl,
+ u8 *hashstate)
{
char vec_name[16];
unsigned int i;
@@ -1262,7 +1474,7 @@ static int test_hash_vec(const char *driver, const struct hash_testvec *vec,
for (i = 0; i < ARRAY_SIZE(default_hash_testvec_configs); i++) {
err = test_hash_vec_cfg(driver, vec, vec_name,
&default_hash_testvec_configs[i],
- req, tsgl, hashstate);
+ req, desc, tsgl, hashstate);
if (err)
return err;
}
@@ -1276,9 +1488,10 @@ static int test_hash_vec(const char *driver, const struct hash_testvec *vec,
generate_random_testvec_config(&cfg, cfgname,
sizeof(cfgname));
err = test_hash_vec_cfg(driver, vec, vec_name, &cfg,
- req, tsgl, hashstate);
+ req, desc, tsgl, hashstate);
if (err)
return err;
+ cond_resched();
}
}
#endif
@@ -1290,14 +1503,12 @@ static int test_hash_vec(const char *driver, const struct hash_testvec *vec,
* Generate a hash test vector from the given implementation.
* Assumes the buffers in 'vec' were already allocated.
*/
-static void generate_random_hash_testvec(struct crypto_shash *tfm,
+static void generate_random_hash_testvec(struct shash_desc *desc,
struct hash_testvec *vec,
unsigned int maxkeysize,
unsigned int maxdatasize,
char *name, size_t max_namelen)
{
- SHASH_DESC_ON_STACK(desc, tfm);
-
/* Data */
vec->psize = generate_random_length(maxdatasize);
generate_random_bytes((u8 *)vec->plaintext, vec->psize);
@@ -1314,7 +1525,7 @@ static void generate_random_hash_testvec(struct crypto_shash *tfm,
vec->ksize = 1 + (prandom_u32() % maxkeysize);
generate_random_bytes((u8 *)vec->key, vec->ksize);
- vec->setkey_error = crypto_shash_setkey(tfm, vec->key,
+ vec->setkey_error = crypto_shash_setkey(desc->tfm, vec->key,
vec->ksize);
/* If the key couldn't be set, no need to continue to digest. */
if (vec->setkey_error)
@@ -1322,7 +1533,6 @@ static void generate_random_hash_testvec(struct crypto_shash *tfm,
}
/* Digest */
- desc->tfm = tfm;
vec->digest_error = crypto_shash_digest(desc, vec->plaintext,
vec->psize, (u8 *)vec->digest);
done:
@@ -1338,6 +1548,7 @@ static int test_hash_vs_generic_impl(const char *driver,
const char *generic_driver,
unsigned int maxkeysize,
struct ahash_request *req,
+ struct shash_desc *desc,
struct test_sglist *tsgl,
u8 *hashstate)
{
@@ -1348,10 +1559,11 @@ static int test_hash_vs_generic_impl(const char *driver,
const char *algname = crypto_hash_alg_common(tfm)->base.cra_name;
char _generic_driver[CRYPTO_MAX_ALG_NAME];
struct crypto_shash *generic_tfm = NULL;
+ struct shash_desc *generic_desc = NULL;
unsigned int i;
struct hash_testvec vec = { 0 };
char vec_name[64];
- struct testvec_config cfg;
+ struct testvec_config *cfg;
char cfgname[TESTVEC_CONFIG_NAMELEN];
int err;
@@ -1381,6 +1593,20 @@ static int test_hash_vs_generic_impl(const char *driver,
return err;
}
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ generic_desc = kzalloc(sizeof(*desc) +
+ crypto_shash_descsize(generic_tfm), GFP_KERNEL);
+ if (!generic_desc) {
+ err = -ENOMEM;
+ goto out;
+ }
+ generic_desc->tfm = generic_tfm;
+
/* Check the algorithm properties for consistency. */
if (digestsize != crypto_shash_digestsize(generic_tfm)) {
@@ -1412,23 +1638,25 @@ static int test_hash_vs_generic_impl(const char *driver,
}
for (i = 0; i < fuzz_iterations * 8; i++) {
- generate_random_hash_testvec(generic_tfm, &vec,
+ generate_random_hash_testvec(generic_desc, &vec,
maxkeysize, maxdatasize,
vec_name, sizeof(vec_name));
- generate_random_testvec_config(&cfg, cfgname, sizeof(cfgname));
+ generate_random_testvec_config(cfg, cfgname, sizeof(cfgname));
- err = test_hash_vec_cfg(driver, &vec, vec_name, &cfg,
- req, tsgl, hashstate);
+ err = test_hash_vec_cfg(driver, &vec, vec_name, cfg,
+ req, desc, tsgl, hashstate);
if (err)
goto out;
cond_resched();
}
err = 0;
out:
+ kfree(cfg);
kfree(vec.key);
kfree(vec.plaintext);
kfree(vec.digest);
crypto_free_shash(generic_tfm);
+ kzfree(generic_desc);
return err;
}
#else /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
@@ -1436,6 +1664,7 @@ static int test_hash_vs_generic_impl(const char *driver,
const char *generic_driver,
unsigned int maxkeysize,
struct ahash_request *req,
+ struct shash_desc *desc,
struct test_sglist *tsgl,
u8 *hashstate)
{
@@ -1443,26 +1672,67 @@ static int test_hash_vs_generic_impl(const char *driver,
}
#endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
+static int alloc_shash(const char *driver, u32 type, u32 mask,
+ struct crypto_shash **tfm_ret,
+ struct shash_desc **desc_ret)
+{
+ struct crypto_shash *tfm;
+ struct shash_desc *desc;
+
+ tfm = crypto_alloc_shash(driver, type, mask);
+ if (IS_ERR(tfm)) {
+ if (PTR_ERR(tfm) == -ENOENT) {
+ /*
+ * This algorithm is only available through the ahash
+ * API, not the shash API, so skip the shash tests.
+ */
+ return 0;
+ }
+ pr_err("alg: hash: failed to allocate shash transform for %s: %ld\n",
+ driver, PTR_ERR(tfm));
+ return PTR_ERR(tfm);
+ }
+
+ desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
+ if (!desc) {
+ crypto_free_shash(tfm);
+ return -ENOMEM;
+ }
+ desc->tfm = tfm;
+
+ *tfm_ret = tfm;
+ *desc_ret = desc;
+ return 0;
+}
+
static int __alg_test_hash(const struct hash_testvec *vecs,
unsigned int num_vecs, const char *driver,
u32 type, u32 mask,
const char *generic_driver, unsigned int maxkeysize)
{
- struct crypto_ahash *tfm;
+ struct crypto_ahash *atfm = NULL;
struct ahash_request *req = NULL;
+ struct crypto_shash *stfm = NULL;
+ struct shash_desc *desc = NULL;
struct test_sglist *tsgl = NULL;
u8 *hashstate = NULL;
+ unsigned int statesize;
unsigned int i;
int err;
- tfm = crypto_alloc_ahash(driver, type, mask);
- if (IS_ERR(tfm)) {
+ /*
+ * Always test the ahash API. This works regardless of whether the
+ * algorithm is implemented as ahash or shash.
+ */
+
+ atfm = crypto_alloc_ahash(driver, type, mask);
+ if (IS_ERR(atfm)) {
pr_err("alg: hash: failed to allocate transform for %s: %ld\n",
- driver, PTR_ERR(tfm));
- return PTR_ERR(tfm);
+ driver, PTR_ERR(atfm));
+ return PTR_ERR(atfm);
}
- req = ahash_request_alloc(tfm, GFP_KERNEL);
+ req = ahash_request_alloc(atfm, GFP_KERNEL);
if (!req) {
pr_err("alg: hash: failed to allocate request for %s\n",
driver);
@@ -1470,6 +1740,14 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
goto out;
}
+ /*
+ * If available also test the shash API, to cover corner cases that may
+ * be missed by testing the ahash API only.
+ */
+ err = alloc_shash(driver, type, mask, &stfm, &desc);
+ if (err)
+ 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",
@@ -1480,8 +1758,10 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
goto out;
}
- hashstate = kmalloc(crypto_ahash_statesize(tfm) + TESTMGR_POISON_LEN,
- GFP_KERNEL);
+ statesize = crypto_ahash_statesize(atfm);
+ if (stfm)
+ statesize = max(statesize, crypto_shash_statesize(stfm));
+ hashstate = kmalloc(statesize + TESTMGR_POISON_LEN, GFP_KERNEL);
if (!hashstate) {
pr_err("alg: hash: failed to allocate hash state buffer for %s\n",
driver);
@@ -1490,20 +1770,24 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
}
for (i = 0; i < num_vecs; i++) {
- err = test_hash_vec(driver, &vecs[i], i, req, tsgl, hashstate);
+ err = test_hash_vec(driver, &vecs[i], i, req, desc, tsgl,
+ hashstate);
if (err)
goto out;
+ cond_resched();
}
err = test_hash_vs_generic_impl(driver, generic_driver, maxkeysize, req,
- tsgl, hashstate);
+ desc, tsgl, hashstate);
out:
kfree(hashstate);
if (tsgl) {
destroy_test_sglist(tsgl);
kfree(tsgl);
}
+ kfree(desc);
+ crypto_free_shash(stfm);
ahash_request_free(req);
- crypto_free_ahash(tfm);
+ crypto_free_ahash(atfm);
return err;
}
@@ -1755,6 +2039,7 @@ static int test_aead_vec(const char *driver, int enc,
&cfg, req, tsgls);
if (err)
return err;
+ cond_resched();
}
}
#endif
@@ -1864,7 +2149,7 @@ static int test_aead_vs_generic_impl(const char *driver,
unsigned int i;
struct aead_testvec vec = { 0 };
char vec_name[64];
- struct testvec_config cfg;
+ struct testvec_config *cfg;
char cfgname[TESTVEC_CONFIG_NAMELEN];
int err;
@@ -1894,6 +2179,12 @@ static int test_aead_vs_generic_impl(const char *driver,
return err;
}
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg) {
+ err = -ENOMEM;
+ goto out;
+ }
+
generic_req = aead_request_alloc(generic_tfm, GFP_KERNEL);
if (!generic_req) {
err = -ENOMEM;
@@ -1948,13 +2239,13 @@ static int test_aead_vs_generic_impl(const char *driver,
generate_random_aead_testvec(generic_req, &vec,
maxkeysize, maxdatasize,
vec_name, sizeof(vec_name));
- generate_random_testvec_config(&cfg, cfgname, sizeof(cfgname));
+ generate_random_testvec_config(cfg, cfgname, sizeof(cfgname));
- err = test_aead_vec_cfg(driver, ENCRYPT, &vec, vec_name, &cfg,
+ err = test_aead_vec_cfg(driver, ENCRYPT, &vec, vec_name, cfg,
req, tsgls);
if (err)
goto out;
- err = test_aead_vec_cfg(driver, DECRYPT, &vec, vec_name, &cfg,
+ err = test_aead_vec_cfg(driver, DECRYPT, &vec, vec_name, cfg,
req, tsgls);
if (err)
goto out;
@@ -1962,6 +2253,7 @@ static int test_aead_vs_generic_impl(const char *driver,
}
err = 0;
out:
+ kfree(cfg);
kfree(vec.key);
kfree(vec.iv);
kfree(vec.assoc);
@@ -1994,6 +2286,7 @@ static int test_aead(const char *driver, int enc,
tsgls);
if (err)
return err;
+ cond_resched();
}
return 0;
}
@@ -2336,6 +2629,7 @@ static int test_skcipher_vec(const char *driver, int enc,
&cfg, req, tsgls);
if (err)
return err;
+ cond_resched();
}
}
#endif
@@ -2409,7 +2703,7 @@ static int test_skcipher_vs_generic_impl(const char *driver,
unsigned int i;
struct cipher_testvec vec = { 0 };
char vec_name[64];
- struct testvec_config cfg;
+ struct testvec_config *cfg;
char cfgname[TESTVEC_CONFIG_NAMELEN];
int err;
@@ -2443,6 +2737,12 @@ static int test_skcipher_vs_generic_impl(const char *driver,
return err;
}
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg) {
+ err = -ENOMEM;
+ goto out;
+ }
+
generic_req = skcipher_request_alloc(generic_tfm, GFP_KERNEL);
if (!generic_req) {
err = -ENOMEM;
@@ -2490,20 +2790,21 @@ static int test_skcipher_vs_generic_impl(const char *driver,
for (i = 0; i < fuzz_iterations * 8; i++) {
generate_random_cipher_testvec(generic_req, &vec, maxdatasize,
vec_name, sizeof(vec_name));
- generate_random_testvec_config(&cfg, cfgname, sizeof(cfgname));
+ generate_random_testvec_config(cfg, cfgname, sizeof(cfgname));
err = test_skcipher_vec_cfg(driver, ENCRYPT, &vec, vec_name,
- &cfg, req, tsgls);
+ cfg, req, tsgls);
if (err)
goto out;
err = test_skcipher_vec_cfg(driver, DECRYPT, &vec, vec_name,
- &cfg, req, tsgls);
+ cfg, req, tsgls);
if (err)
goto out;
cond_resched();
}
err = 0;
out:
+ kfree(cfg);
kfree(vec.key);
kfree(vec.iv);
kfree(vec.ptext);
@@ -2535,6 +2836,7 @@ static int test_skcipher(const char *driver, int enc,
tsgls);
if (err)
return err;
+ cond_resched();
}
return 0;
}
@@ -4125,6 +4427,7 @@ static const struct alg_test_desc alg_test_descs[] = {
}
}, {
.alg = "ecb(arc4)",
+ .generic_driver = "ecb(arc4)-generic",
.test = alg_test_skcipher,
.suite = {
.cipher = __VECS(arc4_tv_template)
@@ -4790,6 +5093,13 @@ static const struct alg_test_desc alg_test_descs[] = {
.test = alg_test_null,
.fips_allowed = 1,
}, {
+ .alg = "xxhash64",
+ .test = alg_test_hash,
+ .fips_allowed = 1,
+ .suite = {
+ .hash = __VECS(xxhash64_tv_template)
+ }
+ }, {
.alg = "zlib-deflate",
.test = alg_test_comp,
.fips_allowed = 1,