3258 lines · 69.4 KB · C
RawDownload
/* * 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> * * 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. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * */ #include <crypto/hash.h>#include <linux/err.h>#include <linux/module.h>#include <linux/scatterlist.h>#include <linux/slab.h>#include <linux/string.h>#include <crypto/rng.h> #include "internal.h" #ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS /* 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 /* * Indexes into the xbuf to simulate cross-page access. */#define IDX1		32#define IDX2		32400#define IDX3		1#define IDX4		8193#define IDX5		22222#define IDX6		17101#define IDX7		27333#define IDX8		3000 /** Used by test_cipher()*/#define ENCRYPT 1#define DECRYPT 0 struct tcrypt_result {	struct completion completion;	int err;}; struct aead_test_suite {	struct {		struct aead_testvec *vecs;		unsigned int count;	} enc, dec;}; struct cipher_test_suite {	struct {		struct cipher_testvec *vecs;		unsigned int count;	} enc, dec;}; struct comp_test_suite {	struct {		struct comp_testvec *vecs;		unsigned int count;	} comp, decomp;}; struct pcomp_test_suite {	struct {		struct pcomp_testvec *vecs;		unsigned int count;	} comp, decomp;}; struct hash_test_suite {	struct hash_testvec *vecs;	unsigned int count;}; struct cprng_test_suite {	struct cprng_testvec *vecs;	unsigned int count;}; struct alg_test_desc {	const char *alg;	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 pcomp_test_suite pcomp;		struct hash_test_suite hash;		struct cprng_test_suite cprng;	} suite;}; static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; static void hexdump(unsigned char *buf, unsigned int len){	print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,			16, 1,			buf, len, false);} static void tcrypt_complete(struct crypto_async_request *req, int err){	struct tcrypt_result *res = req->data; 	if (err == -EINPROGRESS)		return; 	res->err = err;	complete(&res->completion);} static int testmgr_alloc_buf(char *buf[XBUFSIZE]){	int i; 	for (i = 0; i < XBUFSIZE; i++) {		buf[i] = (void *)__get_free_page(GFP_KERNEL);		if (!buf[i])			goto err_free_buf;	} 	return 0; err_free_buf:	while (i-- > 0)		free_page((unsigned long)buf[i]); 	return -ENOMEM;} static void testmgr_free_buf(char *buf[XBUFSIZE]){	int i; 	for (i = 0; i < XBUFSIZE; i++)		free_page((unsigned long)buf[i]);} static int do_one_async_hash_op(struct ahash_request *req,				struct tcrypt_result *tr,				int ret){	if (ret == -EINPROGRESS || ret == -EBUSY) {		ret = wait_for_completion_interruptible(&tr->completion);		if (!ret)			ret = tr->err;		reinit_completion(&tr->completion);	}	return ret;} static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,		       unsigned int tcount, bool use_digest,		       const int align_offset){	const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm));	unsigned int i, j, k, temp;	struct scatterlist sg[8];	char result[64];	struct ahash_request *req;	struct tcrypt_result tresult;	void *hash_buff;	char *xbuf[XBUFSIZE];	int ret = -ENOMEM; 	if (testmgr_alloc_buf(xbuf))		goto out_nobuf; 	init_completion(&tresult.completion); 	req = ahash_request_alloc(tfm, GFP_KERNEL);	if (!req) {		printk(KERN_ERR "alg: hash: Failed to allocate request for "		       "%s\n", algo);		goto out_noreq;	}	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,				   tcrypt_complete, &tresult); 	j = 0;	for (i = 0; i < tcount; i++) {		if (template[i].np)			continue; 		ret = -EINVAL;		if (WARN_ON(align_offset + template[i].psize > PAGE_SIZE))			goto out; 		j++;		memset(result, 0, 64); 		hash_buff = xbuf[0];		hash_buff += align_offset; 		memcpy(hash_buff, template[i].plaintext, template[i].psize);		sg_init_one(&sg[0], hash_buff, template[i].psize); 		if (template[i].ksize) {			crypto_ahash_clear_flags(tfm, ~0);			ret = crypto_ahash_setkey(tfm, template[i].key,						  template[i].ksize);			if (ret) {				printk(KERN_ERR "alg: hash: setkey failed on "				       "test %d for %s: ret=%d\n", j, algo,				       -ret);				goto out;			}		} 		ahash_request_set_crypt(req, sg, result, template[i].psize);		if (use_digest) {			ret = do_one_async_hash_op(req, &tresult,						   crypto_ahash_digest(req));			if (ret) {				pr_err("alg: hash: digest failed on test %d "				       "for %s: ret=%d\n", j, algo, -ret);				goto out;			}		} else {			ret = do_one_async_hash_op(req, &tresult,						   crypto_ahash_init(req));			if (ret) {				pr_err("alt: hash: init failed on test %d "				       "for %s: ret=%d\n", j, algo, -ret);				goto out;			}			ret = do_one_async_hash_op(req, &tresult,						   crypto_ahash_update(req));			if (ret) {				pr_err("alt: hash: update failed on test %d "				       "for %s: ret=%d\n", j, algo, -ret);				goto out;			}			ret = do_one_async_hash_op(req, &tresult,						   crypto_ahash_final(req));			if (ret) {				pr_err("alt: hash: final failed on test %d "				       "for %s: ret=%d\n", j, algo, -ret);				goto out;			}		} 		if (memcmp(result, template[i].digest,			   crypto_ahash_digestsize(tfm))) {			printk(KERN_ERR "alg: hash: Test %d failed for %s\n",			       j, algo);			hexdump(result, crypto_ahash_digestsize(tfm));			ret = -EINVAL;			goto out;		}	} 	j = 0;	for (i = 0; i < tcount; i++) {		/* alignment tests are only done with continuous buffers */		if (align_offset != 0)			break; 		if (template[i].np) {			j++;			memset(result, 0, 64); 			temp = 0;			sg_init_table(sg, template[i].np);			ret = -EINVAL;			for (k = 0; k < template[i].np; k++) {				if (WARN_ON(offset_in_page(IDX[k]) +					    template[i].tap[k] > PAGE_SIZE))					goto out;				sg_set_buf(&sg[k],					   memcpy(xbuf[IDX[k] >> PAGE_SHIFT] +						  offset_in_page(IDX[k]),						  template[i].plaintext + temp,						  template[i].tap[k]),					   template[i].tap[k]);				temp += template[i].tap[k];			} 			if (template[i].ksize) {				crypto_ahash_clear_flags(tfm, ~0);				ret = crypto_ahash_setkey(tfm, template[i].key,							  template[i].ksize); 				if (ret) {					printk(KERN_ERR "alg: hash: setkey "					       "failed on chunking test %d "					       "for %s: ret=%d\n", j, algo,					       -ret);					goto out;				}			} 			ahash_request_set_crypt(req, sg, result,						template[i].psize);			ret = crypto_ahash_digest(req);			switch (ret) {			case 0:				break;			case -EINPROGRESS:			case -EBUSY:				ret = wait_for_completion_interruptible(					&tresult.completion);				if (!ret && !(ret = tresult.err)) {					reinit_completion(&tresult.completion);					break;				}				/* fall through */			default:				printk(KERN_ERR "alg: hash: digest failed "				       "on chunking test %d for %s: "				       "ret=%d\n", j, algo, -ret);				goto out;			} 			if (memcmp(result, template[i].digest,				   crypto_ahash_digestsize(tfm))) {				printk(KERN_ERR "alg: hash: Chunking test %d "				       "failed for %s\n", j, algo);				hexdump(result, crypto_ahash_digestsize(tfm));				ret = -EINVAL;				goto out;			}		}	} 	ret = 0; out:	ahash_request_free(req);out_noreq:	testmgr_free_buf(xbuf);out_nobuf:	return ret;} static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,		     unsigned int tcount, bool use_digest){	unsigned int alignmask;	int ret; 	ret = __test_hash(tfm, template, tcount, use_digest, 0);	if (ret)		return ret; 	/* test unaligned buffers, check with one byte offset */	ret = __test_hash(tfm, template, tcount, use_digest, 1);	if (ret)		return ret; 	alignmask = crypto_tfm_alg_alignmask(&tfm->base);	if (alignmask) {		/* Check if alignment mask for tfm is correctly set. */		ret = __test_hash(tfm, template, tcount, use_digest,				  alignmask + 1);		if (ret)			return ret;	} 	return 0;} static int __test_aead(struct crypto_aead *tfm, int enc,		       struct aead_testvec *template, unsigned int tcount,		       const bool diff_dst, const int align_offset){	const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm));	unsigned int i, j, k, n, temp;	int ret = -ENOMEM;	char *q;	char *key;	struct aead_request *req;	struct scatterlist *sg;	struct scatterlist *asg;	struct scatterlist *sgout;	const char *e, *d;	struct tcrypt_result result;	unsigned int authsize;	void *input;	void *output;	void *assoc;	char iv[MAX_IVLEN];	char *xbuf[XBUFSIZE];	char *xoutbuf[XBUFSIZE];	char *axbuf[XBUFSIZE]; 	if (testmgr_alloc_buf(xbuf))		goto out_noxbuf;	if (testmgr_alloc_buf(axbuf))		goto out_noaxbuf; 	if (diff_dst && testmgr_alloc_buf(xoutbuf))		goto out_nooutbuf; 	/* avoid "the frame size is larger than 1024 bytes" compiler warning */	sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 3 : 2), GFP_KERNEL);	if (!sg)		goto out_nosg;	asg = &sg[8];	sgout = &asg[8]; 	if (diff_dst)		d = "-ddst";	else		d = ""; 	if (enc == ENCRYPT)		e = "encryption";	else		e = "decryption"; 	init_completion(&result.completion); 	req = aead_request_alloc(tfm, GFP_KERNEL);	if (!req) {		pr_err("alg: aead%s: Failed to allocate request for %s\n",		       d, algo);		goto out;	} 	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,				  tcrypt_complete, &result); 	for (i = 0, j = 0; i < tcount; i++) {		if (!template[i].np) {			j++; 			/* some templates have no input data but they will			 * touch input			 */			input = xbuf[0];			input += align_offset;			assoc = axbuf[0]; 			ret = -EINVAL;			if (WARN_ON(align_offset + template[i].ilen >				    PAGE_SIZE || template[i].alen > PAGE_SIZE))				goto out; 			memcpy(input, template[i].input, template[i].ilen);			memcpy(assoc, template[i].assoc, template[i].alen);			if (template[i].iv)				memcpy(iv, template[i].iv, MAX_IVLEN);			else				memset(iv, 0, MAX_IVLEN); 			crypto_aead_clear_flags(tfm, ~0);			if (template[i].wk)				crypto_aead_set_flags(					tfm, CRYPTO_TFM_REQ_WEAK_KEY); 			key = template[i].key; 			ret = crypto_aead_setkey(tfm, key,						 template[i].klen);			if (!ret == template[i].fail) {				pr_err("alg: aead%s: setkey failed on test %d for %s: flags=%x\n",				       d, j, algo, crypto_aead_get_flags(tfm));				goto out;			} else if (ret)				continue; 			authsize = abs(template[i].rlen - template[i].ilen);			ret = crypto_aead_setauthsize(tfm, authsize);			if (ret) {

Lines 1–500 of 3258.