From: Eric Biggers <ebiggers@kernel.org>
To: linux-crypto@vger.kernel.org
Subject: [RFC/RFT PATCH 15/18] crypto: testmgr - fuzz hashes against their generic implementation
Date: Sun, 31 Mar 2019 13:04:25 -0700 [thread overview]
Message-ID: <20190331200428.26597-16-ebiggers@kernel.org> (raw)
In-Reply-To: <20190331200428.26597-1-ebiggers@kernel.org>
From: Eric Biggers <ebiggers@google.com>
When the extra crypto self-tests are enabled, test each hash algorithm
against its generic implementation when one is available. This
involves: checking the algorithm properties for consistency, then
randomly generating test vectors using the generic implementation and
running them against the implementation under test. Both bad and good
inputs are tested.
This has already detected a bug in the x86 implementation of poly1305,
bugs in crct10dif, and an inconsistency in cbcmac.
Signed-off-by: Eric Biggers <ebiggers@google.com>
---
crypto/testmgr.c | 174 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 170 insertions(+), 4 deletions(-)
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index edbb5001cad58..6f5e85b3d17db 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -1286,9 +1286,169 @@ static int test_hash_vec(const char *driver, const struct hash_testvec *vec,
return 0;
}
+#ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
+/*
+ * 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,
+ 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);
+
+ /*
+ * Key: length in range [1, maxkeysize], but usually choose maxkeysize.
+ * If algorithm is unkeyed, then maxkeysize == 0 and set ksize = 0.
+ */
+ vec->setkey_error = 0;
+ vec->ksize = 0;
+ if (maxkeysize) {
+ vec->ksize = maxkeysize;
+ if (prandom_u32() % 4 == 0)
+ vec->ksize = 1 + (prandom_u32() % maxkeysize);
+ generate_random_bytes((u8 *)vec->key, vec->ksize);
+
+ vec->setkey_error = crypto_shash_setkey(tfm, vec->key,
+ vec->ksize);
+ /* If the key couldn't be set, no need to continue to digest. */
+ if (vec->setkey_error)
+ goto done;
+ }
+
+ /* Digest */
+ desc->tfm = tfm;
+ desc->flags = 0;
+ vec->digest_error = crypto_shash_digest(desc, vec->plaintext,
+ vec->psize, (u8 *)vec->digest);
+done:
+ snprintf(name, max_namelen, "\"random: psize=%u ksize=%u\"",
+ vec->psize, vec->ksize);
+}
+
+/*
+ * Test the hash algorithm represented by @req against the corresponding generic
+ * implementation, if one is available.
+ */
+static int test_hash_vs_generic_impl(const char *driver,
+ const char *generic_driver,
+ unsigned int maxkeysize,
+ struct ahash_request *req,
+ struct test_sglist *tsgl,
+ u8 *hashstate)
+{
+ struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+ const unsigned int digestsize = crypto_ahash_digestsize(tfm);
+ const unsigned int blocksize = crypto_ahash_blocksize(tfm);
+ const unsigned int maxdatasize = (2 * PAGE_SIZE) - TESTMGR_POISON_LEN;
+ const char *algname = tfm->base.__crt_alg->cra_name;
+ char _generic_driver[CRYPTO_MAX_ALG_NAME];
+ struct crypto_shash *generic_tfm = NULL;
+ unsigned int i;
+ struct hash_testvec vec = { 0 };
+ char vec_name[64];
+ struct testvec_config cfg;
+ char cfgname[TESTVEC_CONFIG_NAMELEN];
+ int err;
+
+ if (noextratests)
+ return 0;
+
+ if (!generic_driver) { /* Use default naming convention? */
+ err = build_generic_driver_name(algname, _generic_driver);
+ if (err)
+ return err;
+ generic_driver = _generic_driver;
+ }
+
+ if (strcmp(generic_driver, driver) == 0) /* Already the generic impl? */
+ return 0;
+
+ generic_tfm = crypto_alloc_shash(generic_driver, 0, 0);
+ if (IS_ERR(generic_tfm)) {
+ err = PTR_ERR(generic_tfm);
+ if (err == -ENOENT) {
+ pr_warn("alg: hash: skipping comparison tests for %s because %s is unavailable\n",
+ driver, generic_driver);
+ return 0;
+ }
+ pr_err("alg: hash: error allocating %s (generic impl of %s): %d\n",
+ generic_driver, algname, err);
+ return err;
+ }
+
+ /* Check the algorithm properties for consistency. */
+
+ if (digestsize != crypto_shash_digestsize(generic_tfm)) {
+ pr_err("alg: hash: digestsize for %s (%u) doesn't match generic impl (%u)\n",
+ driver, digestsize,
+ crypto_shash_digestsize(generic_tfm));
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (blocksize != crypto_shash_blocksize(generic_tfm)) {
+ pr_err("alg: hash: blocksize for %s (%u) doesn't match generic impl (%u)\n",
+ driver, blocksize, crypto_shash_blocksize(generic_tfm));
+ err = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Now generate test vectors using the generic implementation, and test
+ * the other implementation against them.
+ */
+
+ vec.key = kmalloc(maxkeysize, GFP_KERNEL);
+ vec.plaintext = kmalloc(maxdatasize, GFP_KERNEL);
+ vec.digest = kmalloc(digestsize, GFP_KERNEL);
+ if (!vec.key || !vec.plaintext || !vec.digest) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < fuzz_iterations * 8; i++) {
+ generate_random_hash_testvec(generic_tfm, &vec,
+ maxkeysize, maxdatasize,
+ vec_name, sizeof(vec_name));
+ generate_random_testvec_config(&cfg, cfgname, sizeof(cfgname));
+
+ err = test_hash_vec_cfg(driver, &vec, vec_name, &cfg,
+ req, tsgl, hashstate);
+ if (err)
+ goto out;
+ cond_resched();
+ }
+ err = 0;
+out:
+ kfree(vec.key);
+ kfree(vec.plaintext);
+ kfree(vec.digest);
+ crypto_free_shash(generic_tfm);
+ return err;
+}
+#else /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
+static int test_hash_vs_generic_impl(const char *driver,
+ const char *generic_driver,
+ unsigned int maxkeysize,
+ struct ahash_request *req,
+ struct test_sglist *tsgl,
+ u8 *hashstate)
+{
+ return 0;
+}
+#endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
+
static int __alg_test_hash(const struct hash_testvec *vecs,
unsigned int num_vecs, const char *driver,
- u32 type, u32 mask)
+ u32 type, u32 mask,
+ const char *generic_driver, unsigned int maxkeysize)
{
struct crypto_ahash *tfm;
struct ahash_request *req = NULL;
@@ -1336,7 +1496,8 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
if (err)
goto out;
}
- err = 0;
+ err = test_hash_vs_generic_impl(driver, generic_driver, maxkeysize, req,
+ tsgl, hashstate);
out:
kfree(hashstate);
if (tsgl) {
@@ -1354,6 +1515,7 @@ static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
const struct hash_testvec *template = desc->suite.hash.vecs;
unsigned int tcount = desc->suite.hash.count;
unsigned int nr_unkeyed, nr_keyed;
+ unsigned int maxkeysize = 0;
int err;
/*
@@ -1372,16 +1534,20 @@ static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
"unkeyed ones must come first\n", desc->alg);
return -EINVAL;
}
+ maxkeysize = max_t(unsigned int, maxkeysize,
+ template[nr_unkeyed + nr_keyed].ksize);
}
err = 0;
if (nr_unkeyed) {
- err = __alg_test_hash(template, nr_unkeyed, driver, type, mask);
+ err = __alg_test_hash(template, nr_unkeyed, driver, type, mask,
+ desc->generic_driver, maxkeysize);
template += nr_unkeyed;
}
if (!err && nr_keyed)
- err = __alg_test_hash(template, nr_keyed, driver, type, mask);
+ err = __alg_test_hash(template, nr_keyed, driver, type, mask,
+ desc->generic_driver, maxkeysize);
return err;
}
--
2.21.0
next prev parent reply other threads:[~2019-03-31 20:06 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-03-31 20:04 [RFC/RFT PATCH 00/18] crypto: fuzz algorithms against their generic implementation Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 01/18] crypto: x86/poly1305 - fix overflow during partial reduction Eric Biggers
2019-04-01 7:52 ` Martin Willi
2019-03-31 20:04 ` [RFC/RFT PATCH 02/18] crypto: crct10dif-generic - fix use via crypto_shash_digest() Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 03/18] crypto: x86/crct10dif-pcl " Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 04/18] crypto: skcipher - restore default skcipher_walk::iv on error Eric Biggers
2019-04-08 6:23 ` Herbert Xu
2019-04-08 17:27 ` Eric Biggers
2019-04-09 6:37 ` Herbert Xu
2019-03-31 20:04 ` [RFC/RFT PATCH 05/18] crypto: skcipher - don't WARN on unprocessed data after slow walk step Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 06/18] crypto: chacha20poly1305 - set cra_name correctly Eric Biggers
2019-04-01 7:57 ` Martin Willi
2019-03-31 20:04 ` [RFC/RFT PATCH 07/18] crypto: gcm - fix incompatibility between "gcm" and "gcm_base" Eric Biggers
2019-04-01 15:56 ` Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 08/18] crypto: ccm - fix incompatibility between "ccm" and "ccm_base" Eric Biggers
2019-04-02 15:48 ` Sasha Levin
2019-03-31 20:04 ` [RFC/RFT PATCH 09/18] crypto: streebog - fix unaligned memory accesses Eric Biggers
2019-03-31 21:47 ` Vitaly Chikunov
2019-04-02 16:15 ` Vitaly Chikunov
2019-04-02 16:57 ` Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 10/18] crypto: cts - don't support empty messages Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 11/18] crypto: arm64/cbcmac - handle empty messages in same way as template Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 12/18] crypto: testmgr - expand ability to test for errors Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 13/18] crypto: testmgr - identify test vectors by name rather than number Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 14/18] crypto: testmgr - add helpers for fuzzing against generic implementation Eric Biggers
2019-03-31 20:04 ` Eric Biggers [this message]
2019-03-31 20:04 ` [RFC/RFT PATCH 16/18] crypto: testmgr - fuzz skciphers against their " Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 17/18] crypto: testmgr - fuzz AEADs " Eric Biggers
2019-03-31 20:04 ` [RFC/RFT PATCH 18/18] crypto: run initcalls for generic implementations earlier Eric Biggers
2019-04-08 5:53 ` Herbert Xu
2019-04-08 17:44 ` Eric Biggers
2019-04-09 6:24 ` Herbert Xu
2019-04-09 18:16 ` Eric Biggers
2019-04-11 6:26 ` Herbert Xu
2019-04-08 6:44 ` [RFC/RFT PATCH 00/18] crypto: fuzz algorithms against their generic implementation Herbert Xu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190331200428.26597-16-ebiggers@kernel.org \
--to=ebiggers@kernel.org \
--cc=linux-crypto@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).