diff options
Diffstat (limited to 'crypto/testmgr.c')
| -rw-r--r-- | crypto/testmgr.c | 613 | 
1 files changed, 185 insertions, 428 deletions
diff --git a/crypto/testmgr.c b/crypto/testmgr.c index a275c7c2c371..6a870e21b0cf 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1208,443 +1208,222 @@ static int test_hash(struct crypto_ahash *tfm,  	return 0;  } -static int __test_aead(struct crypto_aead *tfm, int enc, -		       const struct aead_testvec *template, unsigned int tcount, -		       const bool diff_dst, const int align_offset) +static int test_aead_vec_cfg(const char *driver, int enc, +			     const struct aead_testvec *vec, +			     unsigned int vec_num, +			     const struct testvec_config *cfg, +			     struct aead_request *req, +			     struct cipher_test_sglists *tsgls)  { -	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 *sgout; -	const char *e, *d; -	struct crypto_wait wait; -	unsigned int authsize, iv_len; -	char *iv; -	char *xbuf[XBUFSIZE]; -	char *xoutbuf[XBUFSIZE]; -	char *axbuf[XBUFSIZE]; - -	iv = kzalloc(MAX_IVLEN, GFP_KERNEL); -	if (!iv) -		return ret; -	key = kmalloc(MAX_KEYLEN, GFP_KERNEL); -	if (!key) -		goto out_noxbuf; -	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(array3_size(sizeof(*sg), 8, (diff_dst ? 4 : 2)), -		     GFP_KERNEL); -	if (!sg) -		goto out_nosg; -	sgout = &sg[16]; - -	if (diff_dst) -		d = "-ddst"; -	else -		d = ""; +	struct crypto_aead *tfm = crypto_aead_reqtfm(req); +	const unsigned int alignmask = crypto_aead_alignmask(tfm); +	const unsigned int ivsize = crypto_aead_ivsize(tfm); +	const unsigned int authsize = vec->clen - vec->plen; +	const u32 req_flags = CRYPTO_TFM_REQ_MAY_BACKLOG | cfg->req_flags; +	const char *op = enc ? "encryption" : "decryption"; +	DECLARE_CRYPTO_WAIT(wait); +	u8 _iv[3 * (MAX_ALGAPI_ALIGNMASK + 1) + MAX_IVLEN]; +	u8 *iv = PTR_ALIGN(&_iv[0], 2 * (MAX_ALGAPI_ALIGNMASK + 1)) + +		 cfg->iv_offset + +		 (cfg->iv_offset_relative_to_alignmask ? alignmask : 0); +	struct kvec input[2]; +	int err; -	if (enc == ENCRYPT) -		e = "encryption"; +	/* Set the key */ +	if (vec->wk) +		crypto_aead_set_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS);  	else -		e = "decryption"; - -	crypto_init_wait(&wait); - -	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; +		crypto_aead_clear_flags(tfm, CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); +	err = crypto_aead_setkey(tfm, vec->key, vec->klen); +	if (err) { +		if (vec->fail) /* expectedly failed to set key? */ +			return 0; +		pr_err("alg: aead: %s setkey failed with err %d on test vector %u; flags=%#x\n", +		       driver, err, vec_num, crypto_aead_get_flags(tfm)); +		return err;  	} - -	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, -				  crypto_req_done, &wait); - -	iv_len = crypto_aead_ivsize(tfm); - -	for (i = 0, j = 0; i < tcount; i++) { -		const char *input, *expected_output; -		unsigned int inlen, outlen; -		char *inbuf, *outbuf, *assocbuf; - -		if (template[i].np) -			continue; -		if (enc) { -			if (template[i].novrfy) -				continue; -			input = template[i].ptext; -			inlen = template[i].plen; -			expected_output = template[i].ctext; -			outlen = template[i].clen; -		} else { -			input = template[i].ctext; -			inlen = template[i].clen; -			expected_output = template[i].ptext; -			outlen = template[i].plen; -		} - -		j++; - -		/* some templates have no input data but they will -		 * touch input -		 */ -		inbuf = xbuf[0] + align_offset; -		assocbuf = axbuf[0]; - -		ret = -EINVAL; -		if (WARN_ON(align_offset + template[i].clen > PAGE_SIZE || -			    template[i].alen > PAGE_SIZE)) -			goto out; - -		memcpy(inbuf, input, inlen); -		memcpy(assocbuf, template[i].assoc, template[i].alen); -		if (template[i].iv) -			memcpy(iv, template[i].iv, iv_len); -		else -			memset(iv, 0, iv_len); - -		crypto_aead_clear_flags(tfm, ~0); -		if (template[i].wk) -			crypto_aead_set_flags(tfm, -					      CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); - -		if (template[i].klen > MAX_KEYLEN) { -			pr_err("alg: aead%s: setkey failed on test %d for %s: key size %d > %d\n", -			       d, j, algo, template[i].klen, -			       MAX_KEYLEN); -			ret = -EINVAL; -			goto out; -		} -		memcpy(key, template[i].key, template[i].klen); - -		ret = crypto_aead_setkey(tfm, key, template[i].klen); -		if (template[i].fail == !ret) { -			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 = template[i].clen - template[i].plen; -		ret = crypto_aead_setauthsize(tfm, authsize); -		if (ret) { -			pr_err("alg: aead%s: Failed to set authsize to %u on test %d for %s\n", -			       d, authsize, j, algo); -			goto out; -		} - -		k = !!template[i].alen; -		sg_init_table(sg, k + 1); -		sg_set_buf(&sg[0], assocbuf, template[i].alen); -		sg_set_buf(&sg[k], inbuf, template[i].clen); -		outbuf = inbuf; - -		if (diff_dst) { -			sg_init_table(sgout, k + 1); -			sg_set_buf(&sgout[0], assocbuf, template[i].alen); - -			outbuf = xoutbuf[0] + align_offset; -			sg_set_buf(&sgout[k], outbuf, template[i].clen); -		} - -		aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, inlen, -				       iv); - -		aead_request_set_ad(req, template[i].alen); - -		ret = crypto_wait_req(enc ? crypto_aead_encrypt(req) -				      : crypto_aead_decrypt(req), &wait); - -		switch (ret) { -		case 0: -			if (template[i].novrfy) { -				/* verification was supposed to fail */ -				pr_err("alg: aead%s: %s failed on test %d for %s: ret was 0, expected -EBADMSG\n", -				       d, e, j, algo); -				/* so really, we got a bad message */ -				ret = -EBADMSG; -				goto out; -			} -			break; -		case -EBADMSG: -			if (template[i].novrfy) -				/* verification failure was expected */ -				continue; -			/* fall through */ -		default: -			pr_err("alg: aead%s: %s failed on test %d for %s: ret=%d\n", -			       d, e, j, algo, -ret); -			goto out; -		} - -		if (memcmp(outbuf, expected_output, outlen)) { -			pr_err("alg: aead%s: Test %d failed on %s for %s\n", -			       d, j, e, algo); -			hexdump(outbuf, outlen); -			ret = -EINVAL; -			goto out; -		} +	if (vec->fail) { +		pr_err("alg: aead: %s setkey unexpectedly succeeded on test vector %u\n", +		       driver, vec_num); +		return -EINVAL;  	} -	for (i = 0, j = 0; i < tcount; i++) { -		const char *input, *expected_output; -		unsigned int inlen, outlen; - -		/* alignment tests are only done with continuous buffers */ -		if (align_offset != 0) -			break; - -		if (!template[i].np) -			continue; - -		if (enc) { -			if (template[i].novrfy) -				continue; -			input = template[i].ptext; -			inlen = template[i].plen; -			expected_output = template[i].ctext; -			outlen = template[i].clen; -		} else { -			input = template[i].ctext; -			inlen = template[i].clen; -			expected_output = template[i].ptext; -			outlen = template[i].plen; -		} - -		j++; - -		if (template[i].iv) -			memcpy(iv, template[i].iv, iv_len); -		else -			memset(iv, 0, MAX_IVLEN); - -		crypto_aead_clear_flags(tfm, ~0); -		if (template[i].wk) -			crypto_aead_set_flags(tfm, -					      CRYPTO_TFM_REQ_FORBID_WEAK_KEYS); -		if (template[i].klen > MAX_KEYLEN) { -			pr_err("alg: aead%s: setkey failed on test %d for %s: key size %d > %d\n", -			       d, j, algo, template[i].klen, MAX_KEYLEN); -			ret = -EINVAL; -			goto out; -		} -		memcpy(key, template[i].key, template[i].klen); - -		ret = crypto_aead_setkey(tfm, key, template[i].klen); -		if (template[i].fail == !ret) { -			pr_err("alg: aead%s: setkey failed on chunk test %d for %s: flags=%x\n", -			       d, j, algo, crypto_aead_get_flags(tfm)); -			goto out; -		} else if (ret) -			continue; - -		authsize = template[i].clen - template[i].plen; - -		ret = -EINVAL; -		sg_init_table(sg, template[i].anp + template[i].np); -		if (diff_dst) -			sg_init_table(sgout, template[i].anp + template[i].np); - -		ret = -EINVAL; -		for (k = 0, temp = 0; k < template[i].anp; k++) { -			if (WARN_ON(offset_in_page(IDX[k]) + -				    template[i].atap[k] > PAGE_SIZE)) -				goto out; -			sg_set_buf(&sg[k], -				   memcpy(axbuf[IDX[k] >> PAGE_SHIFT] + -					  offset_in_page(IDX[k]), -					  template[i].assoc + temp, -					  template[i].atap[k]), -				   template[i].atap[k]); -			if (diff_dst) -				sg_set_buf(&sgout[k], -					   axbuf[IDX[k] >> PAGE_SHIFT] + -					   offset_in_page(IDX[k]), -					   template[i].atap[k]); -			temp += template[i].atap[k]; -		} - -		for (k = 0, temp = 0; k < template[i].np; k++) { -			n = template[i].tap[k]; -			if (k == template[i].np - 1 && !enc) -				n += authsize; - -			if (WARN_ON(offset_in_page(IDX[k]) + n > PAGE_SIZE)) -				goto out; - -			q = xbuf[IDX[k] >> PAGE_SHIFT] + offset_in_page(IDX[k]); -			memcpy(q, input + temp, n); -			sg_set_buf(&sg[template[i].anp + k], q, n); - -			if (diff_dst) { -				q = xoutbuf[IDX[k] >> PAGE_SHIFT] + -				    offset_in_page(IDX[k]); - -				memset(q, 0, n); - -				sg_set_buf(&sgout[template[i].anp + k], q, n); -			} - -			if (k == template[i].np - 1 && enc) -				n += authsize; -			if (offset_in_page(q) + n < PAGE_SIZE) -				q[n] = 0; - -			temp += n; -		} +	/* Set the authentication tag size */ +	err = crypto_aead_setauthsize(tfm, authsize); +	if (err) { +		pr_err("alg: aead: %s setauthsize failed with err %d on test vector %u\n", +		       driver, err, vec_num); +		return err; +	} -		ret = crypto_aead_setauthsize(tfm, authsize); -		if (ret) { -			pr_err("alg: aead%s: Failed to set authsize to %u on chunk test %d for %s\n", -			       d, authsize, j, algo); -			goto out; -		} +	/* The IV must be copied to a buffer, as the algorithm may modify it */ +	if (WARN_ON(ivsize > MAX_IVLEN)) +		return -EINVAL; +	if (vec->iv) +		memcpy(iv, vec->iv, ivsize); +	else +		memset(iv, 0, ivsize); -		if (enc) { -			if (WARN_ON(sg[template[i].anp + k - 1].offset + -				    sg[template[i].anp + k - 1].length + -				    authsize > PAGE_SIZE)) { -				ret = -EINVAL; -				goto out; -			} +	/* Build the src/dst scatterlists */ +	input[0].iov_base = (void *)vec->assoc; +	input[0].iov_len = vec->alen; +	input[1].iov_base = enc ? (void *)vec->ptext : (void *)vec->ctext; +	input[1].iov_len = enc ? vec->plen : vec->clen; +	err = build_cipher_test_sglists(tsgls, cfg, alignmask, +					vec->alen + (enc ? vec->plen : +						     vec->clen), +					vec->alen + (enc ? vec->clen : +						     vec->plen), +					input, 2); +	if (err) { +		pr_err("alg: aead: %s %s: error preparing scatterlists for test vector %u, cfg=\"%s\"\n", +		       driver, op, vec_num, cfg->name); +		return err; +	} -			if (diff_dst) -				sgout[template[i].anp + k - 1].length += -					authsize; -			sg[template[i].anp + k - 1].length += authsize; -		} +	/* Do the actual encryption or decryption */ +	testmgr_poison(req->__ctx, crypto_aead_reqsize(tfm)); +	aead_request_set_callback(req, req_flags, crypto_req_done, &wait); +	aead_request_set_crypt(req, tsgls->src.sgl_ptr, tsgls->dst.sgl_ptr, +			       enc ? vec->plen : vec->clen, iv); +	aead_request_set_ad(req, vec->alen); +	err = crypto_wait_req(enc ? crypto_aead_encrypt(req) : +			      crypto_aead_decrypt(req), &wait); -		aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, -				       inlen, iv); +	aead_request_set_tfm(req, tfm); /* TODO: get rid of this */ -		aead_request_set_ad(req, template[i].alen); +	if (err) { +		if (err == -EBADMSG && vec->novrfy) +			return 0; +		pr_err("alg: aead: %s %s failed with err %d on test vector %u, cfg=\"%s\"\n", +		       driver, op, err, vec_num, cfg->name); +		return err; +	} +	if (vec->novrfy) { +		pr_err("alg: aead: %s %s unexpectedly succeeded on test vector %u, cfg=\"%s\"\n", +		       driver, op, vec_num, cfg->name); +		return -EINVAL; +	} -		ret = crypto_wait_req(enc ? crypto_aead_encrypt(req) -				      : crypto_aead_decrypt(req), &wait); +	/* Check for the correct output (ciphertext or plaintext) */ +	err = verify_correct_output(&tsgls->dst, enc ? vec->ctext : vec->ptext, +				    enc ? vec->clen : vec->plen, +				    vec->alen, enc || !cfg->inplace); +	if (err == -EOVERFLOW) { +		pr_err("alg: aead: %s %s overran dst buffer on test vector %u, cfg=\"%s\"\n", +		       driver, op, vec_num, cfg->name); +		return err; +	} +	if (err) { +		pr_err("alg: aead: %s %s test failed (wrong result) on test vector %u, cfg=\"%s\"\n", +		       driver, op, vec_num, cfg->name); +		return err; +	} -		switch (ret) { -		case 0: -			if (template[i].novrfy) { -				/* verification was supposed to fail */ -				pr_err("alg: aead%s: %s failed on chunk test %d for %s: ret was 0, expected -EBADMSG\n", -				       d, e, j, algo); -				/* so really, we got a bad message */ -				ret = -EBADMSG; -				goto out; -			} -			break; -		case -EBADMSG: -			if (template[i].novrfy) -				/* verification failure was expected */ -				continue; -			/* fall through */ -		default: -			pr_err("alg: aead%s: %s failed on chunk test %d for %s: ret=%d\n", -			       d, e, j, algo, -ret); -			goto out; -		} +	return 0; +} -		ret = -EINVAL; -		for (k = 0, temp = 0; k < template[i].np; k++) { -			if (diff_dst) -				q = xoutbuf[IDX[k] >> PAGE_SHIFT] + -				    offset_in_page(IDX[k]); -			else -				q = xbuf[IDX[k] >> PAGE_SHIFT] + -				    offset_in_page(IDX[k]); +static int test_aead_vec(const char *driver, int enc, +			 const struct aead_testvec *vec, unsigned int vec_num, +			 struct aead_request *req, +			 struct cipher_test_sglists *tsgls) +{ +	unsigned int i; +	int err; -			n = template[i].tap[k]; -			if (k == template[i].np - 1 && enc) -				n += authsize; +	if (enc && vec->novrfy) +		return 0; -			if (memcmp(q, expected_output + temp, n)) { -				pr_err("alg: aead%s: Chunk test %d failed on %s at page %u for %s\n", -				       d, j, e, k, algo); -				hexdump(q, n); -				goto out; -			} +	for (i = 0; i < ARRAY_SIZE(default_cipher_testvec_configs); i++) { +		err = test_aead_vec_cfg(driver, enc, vec, vec_num, +					&default_cipher_testvec_configs[i], +					req, tsgls); +		if (err) +			return err; +	} -			q += n; -			if (k == template[i].np - 1 && !enc) { -				if (!diff_dst && memcmp(q, input + temp + n, -							authsize)) -					n = authsize; -				else -					n = 0; -			} else { -				for (n = 0; offset_in_page(q + n) && q[n]; n++) -					; -			} -			if (n) { -				pr_err("alg: aead%s: Result buffer corruption in chunk test %d on %s at page %u for %s: %u bytes:\n", -				       d, j, e, k, algo, n); -				hexdump(q, n); -				goto out; -			} +#ifdef CONFIG_CRYPTO_MANAGER_EXTRA_TESTS +	if (!noextratests) { +		struct testvec_config cfg; +		char cfgname[TESTVEC_CONFIG_NAMELEN]; -			temp += template[i].tap[k]; +		for (i = 0; i < fuzz_iterations; i++) { +			generate_random_testvec_config(&cfg, cfgname, +						       sizeof(cfgname)); +			err = test_aead_vec_cfg(driver, enc, vec, vec_num, +						&cfg, req, tsgls); +			if (err) +				return err;  		}  	} +#endif +	return 0; +} -	ret = 0; +static int test_aead(const char *driver, int enc, +		     const struct aead_test_suite *suite, +		     struct aead_request *req, +		     struct cipher_test_sglists *tsgls) +{ +	unsigned int i; +	int err; -out: -	aead_request_free(req); -	kfree(sg); -out_nosg: -	if (diff_dst) -		testmgr_free_buf(xoutbuf); -out_nooutbuf: -	testmgr_free_buf(axbuf); -out_noaxbuf: -	testmgr_free_buf(xbuf); -out_noxbuf: -	kfree(key); -	kfree(iv); -	return ret; +	for (i = 0; i < suite->count; i++) { +		err = test_aead_vec(driver, enc, &suite->vecs[i], i, req, +				    tsgls); +		if (err) +			return err; +	} +	return 0;  } -static int test_aead(struct crypto_aead *tfm, int enc, -		     const struct aead_testvec *template, unsigned int tcount) +static int alg_test_aead(const struct alg_test_desc *desc, const char *driver, +			 u32 type, u32 mask)  { -	unsigned int alignmask; -	int ret; +	const struct aead_test_suite *suite = &desc->suite.aead; +	struct crypto_aead *tfm; +	struct aead_request *req = NULL; +	struct cipher_test_sglists *tsgls = NULL; +	int err; -	/* test 'dst == src' case */ -	ret = __test_aead(tfm, enc, template, tcount, false, 0); -	if (ret) -		return ret; +	if (suite->count <= 0) { +		pr_err("alg: aead: empty test suite for %s\n", driver); +		return -EINVAL; +	} -	/* test 'dst != src' case */ -	ret = __test_aead(tfm, enc, template, tcount, true, 0); -	if (ret) -		return ret; +	tfm = crypto_alloc_aead(driver, type, mask); +	if (IS_ERR(tfm)) { +		pr_err("alg: aead: failed to allocate transform for %s: %ld\n", +		       driver, PTR_ERR(tfm)); +		return PTR_ERR(tfm); +	} -	/* test unaligned buffers, check with one byte offset */ -	ret = __test_aead(tfm, enc, template, tcount, true, 1); -	if (ret) -		return ret; +	req = aead_request_alloc(tfm, GFP_KERNEL); +	if (!req) { +		pr_err("alg: aead: failed to allocate request for %s\n", +		       driver); +		err = -ENOMEM; +		goto out; +	} -	alignmask = crypto_tfm_alg_alignmask(&tfm->base); -	if (alignmask) { -		/* Check if alignment mask for tfm is correctly set. */ -		ret = __test_aead(tfm, enc, template, tcount, true, -				  alignmask + 1); -		if (ret) -			return ret; +	tsgls = alloc_cipher_test_sglists(); +	if (!tsgls) { +		pr_err("alg: aead: failed to allocate test buffers for %s\n", +		       driver); +		err = -ENOMEM; +		goto out;  	} -	return 0; +	err = test_aead(driver, ENCRYPT, suite, req, tsgls); +	if (err) +		goto out; + +	err = test_aead(driver, DECRYPT, suite, req, tsgls); +out: +	free_cipher_test_sglists(tsgls); +	aead_request_free(req); +	crypto_free_aead(tfm); +	return err;  }  static int test_cipher(struct crypto_cipher *tfm, int enc, @@ -2274,28 +2053,6 @@ out:  	return err;  } -static int alg_test_aead(const struct alg_test_desc *desc, const char *driver, -			 u32 type, u32 mask) -{ -	const struct aead_test_suite *suite = &desc->suite.aead; -	struct crypto_aead *tfm; -	int err; - -	tfm = crypto_alloc_aead(driver, type, mask); -	if (IS_ERR(tfm)) { -		printk(KERN_ERR "alg: aead: Failed to load transform for %s: " -		       "%ld\n", driver, PTR_ERR(tfm)); -		return PTR_ERR(tfm); -	} - -	err = test_aead(tfm, ENCRYPT, suite->vecs, suite->count); -	if (!err) -		err = test_aead(tfm, DECRYPT, suite->vecs, suite->count); - -	crypto_free_aead(tfm); -	return err; -} -  static int alg_test_cipher(const struct alg_test_desc *desc,  			   const char *driver, u32 type, u32 mask)  {  |