[PATCH] crypto: testmgr: allow building a copy as loadable module for testing.

From: Michal Suchanek
Date: Thu Dec 19 2019 - 11:06:45 EST


There is no way to just run the tests built into testmgr. Also it is
rarely possible to build testmgr modular due to KConfig dependencies.

Add a module that does not provide infrastructure, just runs testmgr
tests.

Signed-off-by: Michal Suchanek <msuchanek@xxxxxxx>
---
crypto/Kconfig | 8 ++
crypto/Makefile | 3 +
crypto/alg_test_desc.h | 219 ++++++++++++++++++++++++++++++++++++++
crypto/algboss.c | 2 +
crypto/algboss_runtests.c | 38 +++++++
crypto/testmgr.c | 71 +-----------
crypto/testmgr.h | 146 +------------------------
crypto/testmgr_runtests.c | 1 +
8 files changed, 277 insertions(+), 211 deletions(-)
create mode 100644 crypto/alg_test_desc.h
create mode 100644 crypto/algboss_runtests.c
create mode 120000 crypto/testmgr_runtests.c

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 5575d48473bd..956379b24c74 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -119,6 +119,14 @@ config CRYPTO_MANAGER
Create default cryptographic template instantiations such as
cbc(aes).

+config CRYPTO_MANAGER_RUNTESTS
+ tristate "Cryptographic algorithm manager: test module"
+ depends on CRYPTO_MANAGER2 && !CRYPTO_MANAGER_DISABLE_TESTS
+ default m
+ help
+ Build a module that runs the tests from cryptographic algorithm
+ manager when loaded.
+
config CRYPTO_MANAGER2
def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
select CRYPTO_AEAD2
diff --git a/crypto/Makefile b/crypto/Makefile
index 4ca12b6044f7..c296b27da29e 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -47,6 +47,9 @@ crypto_acompress-y += scompress.o
obj-$(CONFIG_CRYPTO_ACOMP2) += crypto_acompress.o

cryptomgr-y := algboss.o testmgr.o
+cryptomgr_runtests-y := testmgr_runtests.o algboss_runtests.o
+
+obj-$(CONFIG_CRYPTO_MANAGER_RUNTESTS) += cryptomgr_runtests.o

obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o
obj-$(CONFIG_CRYPTO_USER) += crypto_user.o
diff --git a/crypto/alg_test_desc.h b/crypto/alg_test_desc.h
new file mode 100644
index 000000000000..a718092737d0
--- /dev/null
+++ b/crypto/alg_test_desc.h
@@ -0,0 +1,219 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef CRYPTO_ALG_TEST_DESC_H
+#define CRYPTO_ALG_TEST_DESC_H
+
+#include <linux/oid_registry.h>
+
+/*
+ * hash_testvec: structure to describe a hash (message digest) test
+ * @key: Pointer to key (NULL if none)
+ * @plaintext: Pointer to source data
+ * @digest: Pointer to expected digest
+ * @psize: Length of source data in bytes
+ * @ksize: Length of @key in bytes (0 if no key)
+ * @setkey_error: Expected error from setkey()
+ * @digest_error: Expected error from digest()
+ */
+struct hash_testvec {
+ const char *key;
+ const char *plaintext;
+ const char *digest;
+ unsigned int psize;
+ unsigned short ksize;
+ int setkey_error;
+ int digest_error;
+};
+
+/*
+ * cipher_testvec: structure to describe a symmetric cipher test
+ * @key: Pointer to key
+ * @klen: Length of @key in bytes
+ * @iv: Pointer to IV. If NULL, an all-zeroes IV is used.
+ * @iv_out: Pointer to output IV, if applicable for the cipher.
+ * @ptext: Pointer to plaintext
+ * @ctext: Pointer to ciphertext
+ * @len: Length of @ptext and @ctext in bytes
+ * @wk: Does the test need CRYPTO_TFM_REQ_FORBID_WEAK_KEYS?
+ * ( e.g. test needs to fail due to a weak key )
+ * @fips_skip: Skip the test vector in FIPS mode
+ * @generates_iv: Encryption should ignore the given IV, and output @iv_out.
+ * Decryption takes @iv_out. Needed for AES Keywrap ("kw(aes)").
+ * @setkey_error: Expected error from setkey()
+ * @crypt_error: Expected error from encrypt() and decrypt()
+ */
+struct cipher_testvec {
+ const char *key;
+ const char *iv;
+ const char *iv_out;
+ const char *ptext;
+ const char *ctext;
+ unsigned char wk; /* weak key flag */
+ unsigned short klen;
+ unsigned int len;
+ bool fips_skip;
+ bool generates_iv;
+ int setkey_error;
+ int crypt_error;
+};
+
+/*
+ * aead_testvec: structure to describe an AEAD test
+ * @key: Pointer to key
+ * @iv: Pointer to IV. If NULL, an all-zeroes IV is used.
+ * @ptext: Pointer to plaintext
+ * @assoc: Pointer to associated data
+ * @ctext: Pointer to the full authenticated ciphertext. For AEADs that
+ * produce a separate "ciphertext" and "authentication tag", these
+ * two parts are concatenated: ciphertext || tag.
+ * @novrfy: Decryption verification failure expected?
+ * @wk: Does the test need CRYPTO_TFM_REQ_FORBID_WEAK_KEYS?
+ * (e.g. setkey() needs to fail due to a weak key)
+ * @klen: Length of @key in bytes
+ * @plen: Length of @ptext in bytes
+ * @alen: Length of @assoc in bytes
+ * @clen: Length of @ctext in bytes
+ * @setkey_error: Expected error from setkey()
+ * @setauthsize_error: Expected error from setauthsize()
+ * @crypt_error: Expected error from encrypt() and decrypt()
+ */
+struct aead_testvec {
+ const char *key;
+ const char *iv;
+ const char *ptext;
+ const char *assoc;
+ const char *ctext;
+ unsigned char novrfy;
+ unsigned char wk;
+ unsigned char klen;
+ unsigned int plen;
+ unsigned int clen;
+ unsigned int alen;
+ int setkey_error;
+ int setauthsize_error;
+ int crypt_error;
+};
+
+struct cprng_testvec {
+ const char *key;
+ const char *dt;
+ const char *v;
+ const char *result;
+ unsigned char klen;
+ unsigned short dtlen;
+ unsigned short vlen;
+ unsigned short rlen;
+ unsigned short loops;
+};
+
+struct drbg_testvec {
+ const unsigned char *entropy;
+ size_t entropylen;
+ const unsigned char *entpra;
+ const unsigned char *entprb;
+ size_t entprlen;
+ const unsigned char *addtla;
+ const unsigned char *addtlb;
+ size_t addtllen;
+ const unsigned char *pers;
+ size_t perslen;
+ const unsigned char *expected;
+ size_t expectedlen;
+};
+
+struct akcipher_testvec {
+ const unsigned char *key;
+ const unsigned char *params;
+ const unsigned char *m;
+ const unsigned char *c;
+ unsigned int key_len;
+ unsigned int param_len;
+ unsigned int m_size;
+ unsigned int c_size;
+ bool public_key_vec;
+ bool siggen_sigver_test;
+ enum OID algo;
+};
+
+struct kpp_testvec {
+ const unsigned char *secret;
+ const unsigned char *b_secret;
+ const unsigned char *b_public;
+ const unsigned char *expected_a_public;
+ const unsigned char *expected_ss;
+ unsigned short secret_size;
+ unsigned short b_secret_size;
+ unsigned short b_public_size;
+ unsigned short expected_a_public_size;
+ unsigned short expected_ss_size;
+ bool genkey;
+};
+
+
+struct aead_test_suite {
+ const struct aead_testvec *vecs;
+ unsigned int count;
+};
+
+struct cipher_test_suite {
+ const struct cipher_testvec *vecs;
+ unsigned int count;
+};
+
+struct comp_test_suite {
+ struct {
+ const struct comp_testvec *vecs;
+ unsigned int count;
+ } comp, decomp;
+};
+
+struct hash_test_suite {
+ const struct hash_testvec *vecs;
+ unsigned int count;
+};
+
+struct cprng_test_suite {
+ const struct cprng_testvec *vecs;
+ unsigned int count;
+};
+
+struct drbg_test_suite {
+ const struct drbg_testvec *vecs;
+ unsigned int count;
+};
+
+struct akcipher_test_suite {
+ const struct akcipher_testvec *vecs;
+ unsigned int count;
+};
+
+struct kpp_test_suite {
+ const struct kpp_testvec *vecs;
+ unsigned int count;
+};
+
+struct alg_test_desc {
+ const char *alg;
+ const char *generic_driver;
+ int (*test)(const struct alg_test_desc *desc, const char *driver,
+ u32 type, u32 mask);
+ int fips_allowed; /* set if alg is allowed in fips mode */
+
+ union {
+ struct aead_test_suite aead;
+ struct cipher_test_suite cipher;
+ struct comp_test_suite comp;
+ struct hash_test_suite hash;
+ struct cprng_test_suite cprng;
+ struct drbg_test_suite drbg;
+ struct akcipher_test_suite akcipher;
+ struct kpp_test_suite kpp;
+ } suite;
+};
+
+int alg_test_cipher(const struct alg_test_desc *desc,
+ const char *driver, u32 type, u32 mask);
+
+extern const struct alg_test_desc alg_test_descs[];
+extern const int nr_alg_test_descs;
+
+#endif /* CRYPTO_ALG_TEST_DESC_H */
diff --git a/crypto/algboss.c b/crypto/algboss.c
index a62149d6c839..be37c78c7833 100644
--- a/crypto/algboss.c
+++ b/crypto/algboss.c
@@ -300,5 +300,7 @@ static void __exit cryptomgr_exit(void)
arch_initcall(cryptomgr_init);
module_exit(cryptomgr_exit);

+EXPORT_SYMBOL_GPL(alg_test);
+
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Crypto Algorithm Manager");
diff --git a/crypto/algboss_runtests.c b/crypto/algboss_runtests.c
new file mode 100644
index 000000000000..7aa3459cc4fc
--- /dev/null
+++ b/crypto/algboss_runtests.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/module.h>
+#include "alg_test_desc.h"
+
+static int __init testmgr_runtests_init(void)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < nr_alg_test_descs; i++) {
+ const char *alg = alg_test_descs[i].alg;
+ int rc;
+
+ pr_info("Testing %s ...", alg);
+ rc = alg_test_descs[i].test(alg_test_descs + i, alg, 0, 0);
+ switch (rc) {
+ case 0:
+ pr_info("PASSED\n");
+ break;
+ case -2:
+ pr_info("SKIPPED\n");
+ break;
+
+ default:
+ ret = rc;
+ pr_err("%s FAILED(%i)\n", alg, rc);
+ }
+ }
+ return ret;
+}
+
+static void __exit testmgr_runtests_exit(void) {}
+
+module_init(testmgr_runtests_init);
+module_exit(testmgr_runtests_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Crypto Algorithm Manager Test Module");
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index 82513b6b0abd..85d919285e81 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -79,67 +79,6 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
#define ENCRYPT 1
#define DECRYPT 0

-struct aead_test_suite {
- const struct aead_testvec *vecs;
- unsigned int count;
-};
-
-struct cipher_test_suite {
- const struct cipher_testvec *vecs;
- unsigned int count;
-};
-
-struct comp_test_suite {
- struct {
- const struct comp_testvec *vecs;
- unsigned int count;
- } comp, decomp;
-};
-
-struct hash_test_suite {
- const struct hash_testvec *vecs;
- unsigned int count;
-};
-
-struct cprng_test_suite {
- const struct cprng_testvec *vecs;
- unsigned int count;
-};
-
-struct drbg_test_suite {
- const struct drbg_testvec *vecs;
- unsigned int count;
-};
-
-struct akcipher_test_suite {
- const struct akcipher_testvec *vecs;
- unsigned int count;
-};
-
-struct kpp_test_suite {
- const struct kpp_testvec *vecs;
- unsigned int count;
-};
-
-struct alg_test_desc {
- const char *alg;
- const char *generic_driver;
- int (*test)(const struct alg_test_desc *desc, const char *driver,
- u32 type, u32 mask);
- int fips_allowed; /* set if alg is allowed in fips mode */
-
- union {
- struct aead_test_suite aead;
- struct cipher_test_suite cipher;
- struct comp_test_suite comp;
- struct hash_test_suite hash;
- struct cprng_test_suite cprng;
- struct drbg_test_suite drbg;
- struct akcipher_test_suite akcipher;
- struct kpp_test_suite kpp;
- } suite;
-};
-
static void hexdump(unsigned char *buf, unsigned int len)
{
print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
@@ -3232,8 +3171,8 @@ static int test_cprng(struct crypto_rng *tfm,
return err;
}

-static int alg_test_cipher(const struct alg_test_desc *desc,
- const char *driver, u32 type, u32 mask)
+int alg_test_cipher(const struct alg_test_desc *desc,
+ const char *driver, u32 type, u32 mask)
{
const struct cipher_test_suite *suite = &desc->suite.cipher;
struct crypto_cipher *tfm;
@@ -3865,7 +3804,7 @@ static int alg_test_null(const struct alg_test_desc *desc,
#define __VECS(tv) { .vecs = tv, .count = ARRAY_SIZE(tv) }

/* Please keep this list sorted by algorithm name. */
-static const struct alg_test_desc alg_test_descs[] = {
+const struct alg_test_desc alg_test_descs[] = {
{
.alg = "adiantum(xchacha12,aes)",
.generic_driver = "adiantum(xchacha12-generic,aes-generic,nhpoly1305-generic)",
@@ -5204,6 +5143,8 @@ static const struct alg_test_desc alg_test_descs[] = {
}
};

+const int nr_alg_test_descs = ARRAY_SIZE(alg_test_descs);
+
static void alg_check_test_descs_order(void)
{
int i;
@@ -5341,5 +5282,3 @@ int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
}

#endif /* CONFIG_CRYPTO_MANAGER_DISABLE_TESTS */
-
-EXPORT_SYMBOL_GPL(alg_test);
diff --git a/crypto/testmgr.h b/crypto/testmgr.h
index 48da646651cb..378a1bdce74f 100644
--- a/crypto/testmgr.h
+++ b/crypto/testmgr.h
@@ -20,154 +20,10 @@
#ifndef _CRYPTO_TESTMGR_H
#define _CRYPTO_TESTMGR_H

-#include <linux/oid_registry.h>
+#include "alg_test_desc.h"

#define MAX_IVLEN 32

-/*
- * hash_testvec: structure to describe a hash (message digest) test
- * @key: Pointer to key (NULL if none)
- * @plaintext: Pointer to source data
- * @digest: Pointer to expected digest
- * @psize: Length of source data in bytes
- * @ksize: Length of @key in bytes (0 if no key)
- * @setkey_error: Expected error from setkey()
- * @digest_error: Expected error from digest()
- */
-struct hash_testvec {
- const char *key;
- const char *plaintext;
- const char *digest;
- unsigned int psize;
- unsigned short ksize;
- int setkey_error;
- int digest_error;
-};
-
-/*
- * cipher_testvec: structure to describe a symmetric cipher test
- * @key: Pointer to key
- * @klen: Length of @key in bytes
- * @iv: Pointer to IV. If NULL, an all-zeroes IV is used.
- * @iv_out: Pointer to output IV, if applicable for the cipher.
- * @ptext: Pointer to plaintext
- * @ctext: Pointer to ciphertext
- * @len: Length of @ptext and @ctext in bytes
- * @wk: Does the test need CRYPTO_TFM_REQ_FORBID_WEAK_KEYS?
- * ( e.g. test needs to fail due to a weak key )
- * @fips_skip: Skip the test vector in FIPS mode
- * @generates_iv: Encryption should ignore the given IV, and output @iv_out.
- * Decryption takes @iv_out. Needed for AES Keywrap ("kw(aes)").
- * @setkey_error: Expected error from setkey()
- * @crypt_error: Expected error from encrypt() and decrypt()
- */
-struct cipher_testvec {
- const char *key;
- const char *iv;
- const char *iv_out;
- const char *ptext;
- const char *ctext;
- unsigned char wk; /* weak key flag */
- unsigned short klen;
- unsigned int len;
- bool fips_skip;
- bool generates_iv;
- int setkey_error;
- int crypt_error;
-};
-
-/*
- * aead_testvec: structure to describe an AEAD test
- * @key: Pointer to key
- * @iv: Pointer to IV. If NULL, an all-zeroes IV is used.
- * @ptext: Pointer to plaintext
- * @assoc: Pointer to associated data
- * @ctext: Pointer to the full authenticated ciphertext. For AEADs that
- * produce a separate "ciphertext" and "authentication tag", these
- * two parts are concatenated: ciphertext || tag.
- * @novrfy: Decryption verification failure expected?
- * @wk: Does the test need CRYPTO_TFM_REQ_FORBID_WEAK_KEYS?
- * (e.g. setkey() needs to fail due to a weak key)
- * @klen: Length of @key in bytes
- * @plen: Length of @ptext in bytes
- * @alen: Length of @assoc in bytes
- * @clen: Length of @ctext in bytes
- * @setkey_error: Expected error from setkey()
- * @setauthsize_error: Expected error from setauthsize()
- * @crypt_error: Expected error from encrypt() and decrypt()
- */
-struct aead_testvec {
- const char *key;
- const char *iv;
- const char *ptext;
- const char *assoc;
- const char *ctext;
- unsigned char novrfy;
- unsigned char wk;
- unsigned char klen;
- unsigned int plen;
- unsigned int clen;
- unsigned int alen;
- int setkey_error;
- int setauthsize_error;
- int crypt_error;
-};
-
-struct cprng_testvec {
- const char *key;
- const char *dt;
- const char *v;
- const char *result;
- unsigned char klen;
- unsigned short dtlen;
- unsigned short vlen;
- unsigned short rlen;
- unsigned short loops;
-};
-
-struct drbg_testvec {
- const unsigned char *entropy;
- size_t entropylen;
- const unsigned char *entpra;
- const unsigned char *entprb;
- size_t entprlen;
- const unsigned char *addtla;
- const unsigned char *addtlb;
- size_t addtllen;
- const unsigned char *pers;
- size_t perslen;
- const unsigned char *expected;
- size_t expectedlen;
-};
-
-struct akcipher_testvec {
- const unsigned char *key;
- const unsigned char *params;
- const unsigned char *m;
- const unsigned char *c;
- unsigned int key_len;
- unsigned int param_len;
- unsigned int m_size;
- unsigned int c_size;
- bool public_key_vec;
- bool siggen_sigver_test;
- enum OID algo;
-};
-
-struct kpp_testvec {
- const unsigned char *secret;
- const unsigned char *b_secret;
- const unsigned char *b_public;
- const unsigned char *expected_a_public;
- const unsigned char *expected_ss;
- unsigned short secret_size;
- unsigned short b_secret_size;
- unsigned short b_public_size;
- unsigned short expected_a_public_size;
- unsigned short expected_ss_size;
- bool genkey;
-};
-
static const char zeroed_string[48];

/*
diff --git a/crypto/testmgr_runtests.c b/crypto/testmgr_runtests.c
new file mode 120000
index 000000000000..e2a85037239d
--- /dev/null
+++ b/crypto/testmgr_runtests.c
@@ -0,0 +1 @@
+testmgr.c
\ No newline at end of file
--
2.23.0