summaryrefslogtreecommitdiffstats
path: root/crypto/testmgr.c
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2019-04-12 00:57:39 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2019-04-18 10:15:03 -0400
commit9a8a6b3f0950c0df220b684b686c26a902cfcf1a (patch)
treeba47d6fa6fffbc2ff6d2ef1bc2e6abcbaed95c3b /crypto/testmgr.c
parentf2bb770ae89641be0e80b15f12c134689c770ca7 (diff)
crypto: testmgr - fuzz hashes against their generic implementation
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 good and bad 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> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/testmgr.c')
-rw-r--r--crypto/testmgr.c174
1 files changed, 170 insertions, 4 deletions
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index feb3ff27e0b3..cafeba6ba16c 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -1290,9 +1290,169 @@ static int test_hash_vec(const char *driver, const struct hash_testvec *vec,
1290 return 0; 1290 return 0;
1291} 1291}
1292 1292
1293#ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS
1294/*
1295 * Generate a hash test vector from the given implementation.
1296 * Assumes the buffers in 'vec' were already allocated.
1297 */
1298static void generate_random_hash_testvec(struct crypto_shash *tfm,
1299 struct hash_testvec *vec,
1300 unsigned int maxkeysize,
1301 unsigned int maxdatasize,
1302 char *name, size_t max_namelen)
1303{
1304 SHASH_DESC_ON_STACK(desc, tfm);
1305
1306 /* Data */
1307 vec->psize = generate_random_length(maxdatasize);
1308 generate_random_bytes((u8 *)vec->plaintext, vec->psize);
1309
1310 /*
1311 * Key: length in range [1, maxkeysize], but usually choose maxkeysize.
1312 * If algorithm is unkeyed, then maxkeysize == 0 and set ksize = 0.
1313 */
1314 vec->setkey_error = 0;
1315 vec->ksize = 0;
1316 if (maxkeysize) {
1317 vec->ksize = maxkeysize;
1318 if (prandom_u32() % 4 == 0)
1319 vec->ksize = 1 + (prandom_u32() % maxkeysize);
1320 generate_random_bytes((u8 *)vec->key, vec->ksize);
1321
1322 vec->setkey_error = crypto_shash_setkey(tfm, vec->key,
1323 vec->ksize);
1324 /* If the key couldn't be set, no need to continue to digest. */
1325 if (vec->setkey_error)
1326 goto done;
1327 }
1328
1329 /* Digest */
1330 desc->tfm = tfm;
1331 desc->flags = 0;
1332 vec->digest_error = crypto_shash_digest(desc, vec->plaintext,
1333 vec->psize, (u8 *)vec->digest);
1334done:
1335 snprintf(name, max_namelen, "\"random: psize=%u ksize=%u\"",
1336 vec->psize, vec->ksize);
1337}
1338
1339/*
1340 * Test the hash algorithm represented by @req against the corresponding generic
1341 * implementation, if one is available.
1342 */
1343static int test_hash_vs_generic_impl(const char *driver,
1344 const char *generic_driver,
1345 unsigned int maxkeysize,
1346 struct ahash_request *req,
1347 struct test_sglist *tsgl,
1348 u8 *hashstate)
1349{
1350 struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
1351 const unsigned int digestsize = crypto_ahash_digestsize(tfm);
1352 const unsigned int blocksize = crypto_ahash_blocksize(tfm);
1353 const unsigned int maxdatasize = (2 * PAGE_SIZE) - TESTMGR_POISON_LEN;
1354 const char *algname = crypto_hash_alg_common(tfm)->base.cra_name;
1355 char _generic_driver[CRYPTO_MAX_ALG_NAME];
1356 struct crypto_shash *generic_tfm = NULL;
1357 unsigned int i;
1358 struct hash_testvec vec = { 0 };
1359 char vec_name[64];
1360 struct testvec_config cfg;
1361 char cfgname[TESTVEC_CONFIG_NAMELEN];
1362 int err;
1363
1364 if (noextratests)
1365 return 0;
1366
1367 if (!generic_driver) { /* Use default naming convention? */
1368 err = build_generic_driver_name(algname, _generic_driver);
1369 if (err)
1370 return err;
1371 generic_driver = _generic_driver;
1372 }
1373
1374 if (strcmp(generic_driver, driver) == 0) /* Already the generic impl? */
1375 return 0;
1376
1377 generic_tfm = crypto_alloc_shash(generic_driver, 0, 0);
1378 if (IS_ERR(generic_tfm)) {
1379 err = PTR_ERR(generic_tfm);
1380 if (err == -ENOENT) {
1381 pr_warn("alg: hash: skipping comparison tests for %s because %s is unavailable\n",
1382 driver, generic_driver);
1383 return 0;
1384 }
1385 pr_err("alg: hash: error allocating %s (generic impl of %s): %d\n",
1386 generic_driver, algname, err);
1387 return err;
1388 }
1389
1390 /* Check the algorithm properties for consistency. */
1391
1392 if (digestsize != crypto_shash_digestsize(generic_tfm)) {
1393 pr_err("alg: hash: digestsize for %s (%u) doesn't match generic impl (%u)\n",
1394 driver, digestsize,
1395 crypto_shash_digestsize(generic_tfm));
1396 err = -EINVAL;
1397 goto out;
1398 }
1399
1400 if (blocksize != crypto_shash_blocksize(generic_tfm)) {
1401 pr_err("alg: hash: blocksize for %s (%u) doesn't match generic impl (%u)\n",
1402 driver, blocksize, crypto_shash_blocksize(generic_tfm));
1403 err = -EINVAL;
1404 goto out;
1405 }
1406
1407 /*
1408 * Now generate test vectors using the generic implementation, and test
1409 * the other implementation against them.
1410 */
1411
1412 vec.key = kmalloc(maxkeysize, GFP_KERNEL);
1413 vec.plaintext = kmalloc(maxdatasize, GFP_KERNEL);
1414 vec.digest = kmalloc(digestsize, GFP_KERNEL);
1415 if (!vec.key || !vec.plaintext || !vec.digest) {
1416 err = -ENOMEM;
1417 goto out;
1418 }
1419
1420 for (i = 0; i < fuzz_iterations * 8; i++) {
1421 generate_random_hash_testvec(generic_tfm, &vec,
1422 maxkeysize, maxdatasize,
1423 vec_name, sizeof(vec_name));
1424 generate_random_testvec_config(&cfg, cfgname, sizeof(cfgname));
1425
1426 err = test_hash_vec_cfg(driver, &vec, vec_name, &cfg,
1427 req, tsgl, hashstate);
1428 if (err)
1429 goto out;
1430 cond_resched();
1431 }
1432 err = 0;
1433out:
1434 kfree(vec.key);
1435 kfree(vec.plaintext);
1436 kfree(vec.digest);
1437 crypto_free_shash(generic_tfm);
1438 return err;
1439}
1440#else /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
1441static int test_hash_vs_generic_impl(const char *driver,
1442 const char *generic_driver,
1443 unsigned int maxkeysize,
1444 struct ahash_request *req,
1445 struct test_sglist *tsgl,
1446 u8 *hashstate)
1447{
1448 return 0;
1449}
1450#endif /* !CONFIG_CRYPTO_MANAGER_EXTRA_TESTS */
1451
1293static int __alg_test_hash(const struct hash_testvec *vecs, 1452static int __alg_test_hash(const struct hash_testvec *vecs,
1294 unsigned int num_vecs, const char *driver, 1453 unsigned int num_vecs, const char *driver,
1295 u32 type, u32 mask) 1454 u32 type, u32 mask,
1455 const char *generic_driver, unsigned int maxkeysize)
1296{ 1456{
1297 struct crypto_ahash *tfm; 1457 struct crypto_ahash *tfm;
1298 struct ahash_request *req = NULL; 1458 struct ahash_request *req = NULL;
@@ -1340,7 +1500,8 @@ static int __alg_test_hash(const struct hash_testvec *vecs,
1340 if (err) 1500 if (err)
1341 goto out; 1501 goto out;
1342 } 1502 }
1343 err = 0; 1503 err = test_hash_vs_generic_impl(driver, generic_driver, maxkeysize, req,
1504 tsgl, hashstate);
1344out: 1505out:
1345 kfree(hashstate); 1506 kfree(hashstate);
1346 if (tsgl) { 1507 if (tsgl) {
@@ -1358,6 +1519,7 @@ static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
1358 const struct hash_testvec *template = desc->suite.hash.vecs; 1519 const struct hash_testvec *template = desc->suite.hash.vecs;
1359 unsigned int tcount = desc->suite.hash.count; 1520 unsigned int tcount = desc->suite.hash.count;
1360 unsigned int nr_unkeyed, nr_keyed; 1521 unsigned int nr_unkeyed, nr_keyed;
1522 unsigned int maxkeysize = 0;
1361 int err; 1523 int err;
1362 1524
1363 /* 1525 /*
@@ -1376,16 +1538,20 @@ static int alg_test_hash(const struct alg_test_desc *desc, const char *driver,
1376 "unkeyed ones must come first\n", desc->alg); 1538 "unkeyed ones must come first\n", desc->alg);
1377 return -EINVAL; 1539 return -EINVAL;
1378 } 1540 }
1541 maxkeysize = max_t(unsigned int, maxkeysize,
1542 template[nr_unkeyed + nr_keyed].ksize);
1379 } 1543 }
1380 1544
1381 err = 0; 1545 err = 0;
1382 if (nr_unkeyed) { 1546 if (nr_unkeyed) {
1383 err = __alg_test_hash(template, nr_unkeyed, driver, type, mask); 1547 err = __alg_test_hash(template, nr_unkeyed, driver, type, mask,
1548 desc->generic_driver, maxkeysize);
1384 template += nr_unkeyed; 1549 template += nr_unkeyed;
1385 } 1550 }
1386 1551
1387 if (!err && nr_keyed) 1552 if (!err && nr_keyed)
1388 err = __alg_test_hash(template, nr_keyed, driver, type, mask); 1553 err = __alg_test_hash(template, nr_keyed, driver, type, mask,
1554 desc->generic_driver, maxkeysize);
1389 1555
1390 return err; 1556 return err;
1391} 1557}