5722 lines · 148.0 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * Algorithm testing framework and tests. * * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org> * Copyright (c) 2007 Nokia Siemens Networks * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au> * Copyright (c) 2019 Google LLC * * Updated RFC4106 AES-GCM testing. *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com) *             Adrian Hoban <adrian.hoban@intel.com> *             Gabriele Paoloni <gabriele.paoloni@intel.com> *             Tadeusz Struk (tadeusz.struk@intel.com) *    Copyright (c) 2010, Intel Corporation. */ #include <crypto/aead.h>#include <crypto/hash.h>#include <crypto/skcipher.h>#include <linux/err.h>#include <linux/fips.h>#include <linux/module.h>#include <linux/once.h>#include <linux/prandom.h>#include <linux/scatterlist.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/uio.h>#include <crypto/akcipher.h>#include <crypto/kpp.h>#include <crypto/acompress.h>#include <crypto/sig.h>#include <crypto/internal/cipher.h>#include <crypto/internal/rng.h>#include <crypto/internal/simd.h> #include "internal.h" MODULE_IMPORT_NS("CRYPTO_INTERNAL"); static bool notests;module_param(notests, bool, 0644);MODULE_PARM_DESC(notests, "disable all crypto self-tests"); #ifdef CONFIG_CRYPTO_SELFTESTS_FULLstatic bool noslowtests;module_param(noslowtests, bool, 0644);MODULE_PARM_DESC(noslowtests, "disable slow crypto self-tests"); static unsigned int fuzz_iterations = 100;module_param(fuzz_iterations, uint, 0644);MODULE_PARM_DESC(fuzz_iterations, "number of fuzz test iterations");#else#define noslowtests 1#define fuzz_iterations 0#endif #ifndef CONFIG_CRYPTO_SELFTESTS /* a perfect nop */int alg_test(const char *driver, const char *alg, u32 type, u32 mask){	return 0;} #else #include "testmgr.h" /* * Need slab memory for testing (size in number of pages). */#define XBUFSIZE	8 /** Used by test_cipher()*/#define ENCRYPT 1#define DECRYPT 0 struct aead_test_suite {	const struct aead_testvec *vecs;	unsigned int count; 	/*	 * Set if trying to decrypt an inauthentic ciphertext with this	 * algorithm might result in EINVAL rather than EBADMSG, due to other	 * validation the algorithm does on the inputs such as length checks.	 */	unsigned int einval_allowed : 1; 	/*	 * Set if this algorithm requires that the IV be located at the end of	 * the AAD buffer, in addition to being given in the normal way.  The	 * behavior when the two IV copies differ is implementation-defined.	 */	unsigned int aad_iv : 1;}; 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 drbg_test_suite {	const struct drbg_testvec *vecs;	unsigned int count;}; struct akcipher_test_suite {	const struct akcipher_testvec *vecs;	unsigned int count;}; struct sig_test_suite {	const struct sig_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 drbg_test_suite drbg;		struct akcipher_test_suite akcipher;		struct sig_test_suite sig;		struct kpp_test_suite kpp;	} suite;}; static void hexdump(unsigned char *buf, unsigned int len){	print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,			16, 1,			buf, len, false);} static int __testmgr_alloc_buf(char *buf[XBUFSIZE], int order){	int i; 	for (i = 0; i < XBUFSIZE; i++) {		buf[i] = (char *)__get_free_pages(GFP_KERNEL, order);		if (!buf[i])			goto err_free_buf;	} 	return 0; err_free_buf:	while (i-- > 0)		free_pages((unsigned long)buf[i], order); 	return -ENOMEM;} static int testmgr_alloc_buf(char *buf[XBUFSIZE]){	return __testmgr_alloc_buf(buf, 0);} static void __testmgr_free_buf(char *buf[XBUFSIZE], int order){	int i; 	for (i = 0; i < XBUFSIZE; i++)		free_pages((unsigned long)buf[i], order);} static void testmgr_free_buf(char *buf[XBUFSIZE]){	__testmgr_free_buf(buf, 0);} #define TESTMGR_POISON_BYTE	0xfe#define TESTMGR_POISON_LEN	16 static inline void testmgr_poison(void *addr, size_t len){	memset(addr, TESTMGR_POISON_BYTE, len);} /* Is the memory region still fully poisoned? */static inline bool testmgr_is_poison(const void *addr, size_t len){	return memchr_inv(addr, TESTMGR_POISON_BYTE, len) == NULL;} /* flush type for hash algorithms */enum flush_type {	/* merge with update of previous buffer(s) */	FLUSH_TYPE_NONE = 0, 	/* update with previous buffer(s) before doing this one */	FLUSH_TYPE_FLUSH, 	/* likewise, but also export and re-import the intermediate state */	FLUSH_TYPE_REIMPORT,}; /* finalization function for hash algorithms */enum finalization_type {	FINALIZATION_TYPE_FINAL,	/* use final() */	FINALIZATION_TYPE_FINUP,	/* use finup() */	FINALIZATION_TYPE_DIGEST,	/* use digest() */}; /* * Whether the crypto operation will occur in-place, and if so whether the * source and destination scatterlist pointers will coincide (req->src == * req->dst), or whether they'll merely point to two separate scatterlists * (req->src != req->dst) that reference the same underlying memory. * * This is only relevant for algorithm types that support in-place operation. */enum inplace_mode {	OUT_OF_PLACE,	INPLACE_ONE_SGLIST,	INPLACE_TWO_SGLISTS,}; #define TEST_SG_TOTAL	10000 /** * struct test_sg_division - description of a scatterlist entry * * This struct describes one entry of a scatterlist being constructed to check a * crypto test vector. * * @proportion_of_total: length of this chunk relative to the total length, *			 given as a proportion out of TEST_SG_TOTAL so that it *			 scales to fit any test vector * @offset: byte offset into a 2-page buffer at which this chunk will start * @offset_relative_to_alignmask: if true, add the algorithm's alignmask to the *				  @offset * @flush_type: for hashes, whether an update() should be done now vs. *		continuing to accumulate data * @nosimd: if doing the pending update(), do it with SIMD disabled? */struct test_sg_division {	unsigned int proportion_of_total;	unsigned int offset;	bool offset_relative_to_alignmask;	enum flush_type flush_type;	bool nosimd;}; /** * struct testvec_config - configuration for testing a crypto test vector * * This struct describes the data layout and other parameters with which each * crypto test vector can be tested. * * @name: name of this config, logged for debugging purposes if a test fails * @inplace_mode: whether and how to operate on the data in-place, if applicable * @req_flags: extra request_flags, e.g. CRYPTO_TFM_REQ_MAY_SLEEP * @src_divs: description of how to arrange the source scatterlist * @dst_divs: description of how to arrange the dst scatterlist, if applicable *	      for the algorithm type.  Defaults to @src_divs if unset. * @iv_offset: misalignment of the IV in the range [0..MAX_ALGAPI_ALIGNMASK+1], *	       where 0 is aligned to a 2*(MAX_ALGAPI_ALIGNMASK+1) byte boundary * @iv_offset_relative_to_alignmask: if true, add the algorithm's alignmask to *				     the @iv_offset * @key_offset: misalignment of the key, where 0 is default alignment * @key_offset_relative_to_alignmask: if true, add the algorithm's alignmask to *				      the @key_offset * @finalization_type: what finalization function to use for hashes * @nosimd: execute with SIMD disabled?  Requires !CRYPTO_TFM_REQ_MAY_SLEEP. *	    This applies to the parts of the operation that aren't controlled *	    individually by @nosimd_setkey or @src_divs[].nosimd. * @nosimd_setkey: set the key (if applicable) with SIMD disabled?  Requires *		   !CRYPTO_TFM_REQ_MAY_SLEEP. */struct testvec_config {	const char *name;	enum inplace_mode inplace_mode;	u32 req_flags;	struct test_sg_division src_divs[XBUFSIZE];	struct test_sg_division dst_divs[XBUFSIZE];	unsigned int iv_offset;	unsigned int key_offset;	bool iv_offset_relative_to_alignmask;	bool key_offset_relative_to_alignmask;	enum finalization_type finalization_type;	bool nosimd;	bool nosimd_setkey;}; #define TESTVEC_CONFIG_NAMELEN	192 /* * The following are the lists of testvec_configs to test for each algorithm * type when the "fast" crypto self-tests are enabled.  They aim to provide good * test coverage, while keeping the test time much shorter than the "full" tests * so that the "fast" tests can be enabled in a wider range of circumstances. */ /* Configs for skciphers and aeads */static const struct testvec_config default_cipher_testvec_configs[] = {	{		.name = "in-place (one sglist)",		.inplace_mode = INPLACE_ONE_SGLIST,		.src_divs = { { .proportion_of_total = 10000 } },	}, {		.name = "in-place (two sglists)",		.inplace_mode = INPLACE_TWO_SGLISTS,		.src_divs = { { .proportion_of_total = 10000 } },	}, {		.name = "out-of-place",		.inplace_mode = OUT_OF_PLACE,		.src_divs = { { .proportion_of_total = 10000 } },	}, {		.name = "unaligned buffer, offset=1",		.src_divs = { { .proportion_of_total = 10000, .offset = 1 } },		.iv_offset = 1,		.key_offset = 1,	}, {		.name = "buffer aligned only to alignmask",		.src_divs = {			{				.proportion_of_total = 10000,				.offset = 1,				.offset_relative_to_alignmask = true,			},		},		.iv_offset = 1,		.iv_offset_relative_to_alignmask = true,		.key_offset = 1,		.key_offset_relative_to_alignmask = true,	}, {		.name = "two even aligned splits",		.src_divs = {			{ .proportion_of_total = 5000 },			{ .proportion_of_total = 5000 },		},	}, {		.name = "one src, two even splits dst",		.inplace_mode = OUT_OF_PLACE,		.src_divs = { { .proportion_of_total = 10000 } },		.dst_divs = {			{ .proportion_of_total = 5000 },			{ .proportion_of_total = 5000 },		 },	}, {		.name = "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 },		},		.iv_offset = 3,		.key_offset = 3,	}, {		.name = "misaligned splits crossing pages, inplace",		.inplace_mode = INPLACE_ONE_SGLIST,		.src_divs = {			{				.proportion_of_total = 7500,				.offset = PAGE_SIZE - 32			}, {				.proportion_of_total = 2500,				.offset = PAGE_SIZE - 7			},		},	}}; 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,		.key_offset = 1,	}, {		.name = "digest misaligned buffer",		.src_divs = {			{				.proportion_of_total = 10000,				.offset = 1,			},		},		.finalization_type = FINALIZATION_TYPE_DIGEST,		.key_offset = 1,	}, {		.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;	unsigned int ndivs = 0; 	do {		remaining -= divs[ndivs++].proportion_of_total;	} while (remaining); 	return ndivs;} #define SGDIVS_HAVE_FLUSHES	BIT(0)#define SGDIVS_HAVE_NOSIMD	BIT(1) static bool valid_sg_divisions(const struct test_sg_division *divs,			       unsigned int count, int *flags_ret){	unsigned int total = 0;	unsigned int i; 	for (i = 0; i < count && total != TEST_SG_TOTAL; i++) {		if (divs[i].proportion_of_total <= 0 ||		    divs[i].proportion_of_total > TEST_SG_TOTAL - total)			return false;		total += divs[i].proportion_of_total;		if (divs[i].flush_type != FLUSH_TYPE_NONE)			*flags_ret |= SGDIVS_HAVE_FLUSHES;		if (divs[i].nosimd)			*flags_ret |= SGDIVS_HAVE_NOSIMD;	}

Lines 1–500 of 5722.