Commit 64d1cdfb authored by Stephan Mueller's avatar Stephan Mueller Committed by Herbert Xu

crypto: drbg - Add DRBG test code to testmgr

The DRBG test code implements the CAVS test approach.

As discussed for the test vectors, all DRBG types are covered with
testing. However, not every backend cipher is covered with testing. To
prevent the testmgr from logging missing testing, the NULL test is
registered for all backend ciphers not covered with specific test cases.

All currently implemented DRBG types and backend ciphers are defined
in SP800-90A. Therefore, the fips_allowed flag is set for all.
Signed-off-by: default avatarStephan Mueller <smueller@chronox.de>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 3332ee2a
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <crypto/rng.h> #include <crypto/rng.h>
#include <crypto/drbg.h>
#include "internal.h" #include "internal.h"
...@@ -108,6 +109,11 @@ struct cprng_test_suite { ...@@ -108,6 +109,11 @@ struct cprng_test_suite {
unsigned int count; unsigned int count;
}; };
struct drbg_test_suite {
struct drbg_testvec *vecs;
unsigned int count;
};
struct alg_test_desc { struct alg_test_desc {
const char *alg; const char *alg;
int (*test)(const struct alg_test_desc *desc, const char *driver, int (*test)(const struct alg_test_desc *desc, const char *driver,
...@@ -121,6 +127,7 @@ struct alg_test_desc { ...@@ -121,6 +127,7 @@ struct alg_test_desc {
struct pcomp_test_suite pcomp; struct pcomp_test_suite pcomp;
struct hash_test_suite hash; struct hash_test_suite hash;
struct cprng_test_suite cprng; struct cprng_test_suite cprng;
struct drbg_test_suite drbg;
} suite; } suite;
}; };
...@@ -1715,6 +1722,100 @@ static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver, ...@@ -1715,6 +1722,100 @@ static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver,
return err; return err;
} }
static int drbg_cavs_test(struct drbg_testvec *test, int pr,
const char *driver, u32 type, u32 mask)
{
int ret = -EAGAIN;
struct crypto_rng *drng;
struct drbg_test_data test_data;
struct drbg_string addtl, pers, testentropy;
unsigned char *buf = kzalloc(test->expectedlen, GFP_KERNEL);
if (!buf)
return -ENOMEM;
drng = crypto_alloc_rng(driver, type, mask);
if (IS_ERR(drng)) {
printk(KERN_ERR "alg: drbg: could not allocate DRNG handle for"
"%s\n", driver);
kzfree(buf);
return -ENOMEM;
}
test_data.testentropy = &testentropy;
drbg_string_fill(&testentropy, test->entropy, test->entropylen);
drbg_string_fill(&pers, test->pers, test->perslen);
ret = crypto_drbg_reset_test(drng, &pers, &test_data);
if (ret) {
printk(KERN_ERR "alg: drbg: Failed to reset rng\n");
goto outbuf;
}
drbg_string_fill(&addtl, test->addtla, test->addtllen);
if (pr) {
drbg_string_fill(&testentropy, test->entpra, test->entprlen);
ret = crypto_drbg_get_bytes_addtl_test(drng,
buf, test->expectedlen, &addtl, &test_data);
} else {
ret = crypto_drbg_get_bytes_addtl(drng,
buf, test->expectedlen, &addtl);
}
if (ret <= 0) {
printk(KERN_ERR "alg: drbg: could not obtain random data for"
"driver %s\n", driver);
goto outbuf;
}
drbg_string_fill(&addtl, test->addtlb, test->addtllen);
if (pr) {
drbg_string_fill(&testentropy, test->entprb, test->entprlen);
ret = crypto_drbg_get_bytes_addtl_test(drng,
buf, test->expectedlen, &addtl, &test_data);
} else {
ret = crypto_drbg_get_bytes_addtl(drng,
buf, test->expectedlen, &addtl);
}
if (ret <= 0) {
printk(KERN_ERR "alg: drbg: could not obtain random data for"
"driver %s\n", driver);
goto outbuf;
}
ret = memcmp(test->expected, buf, test->expectedlen);
outbuf:
crypto_free_rng(drng);
kzfree(buf);
return ret;
}
static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver,
u32 type, u32 mask)
{
int err = 0;
int pr = 0;
int i = 0;
struct drbg_testvec *template = desc->suite.drbg.vecs;
unsigned int tcount = desc->suite.drbg.count;
if (0 == memcmp(driver, "drbg_pr_", 8))
pr = 1;
for (i = 0; i < tcount; i++) {
err = drbg_cavs_test(&template[i], pr, driver, type, mask);
if (err) {
printk(KERN_ERR "alg: drbg: Test %d failed for %s\n",
i, driver);
err = -EINVAL;
break;
}
}
return err;
}
static int alg_test_null(const struct alg_test_desc *desc, static int alg_test_null(const struct alg_test_desc *desc,
const char *driver, u32 type, u32 mask) const char *driver, u32 type, u32 mask)
{ {
...@@ -2457,6 +2558,152 @@ static const struct alg_test_desc alg_test_descs[] = { ...@@ -2457,6 +2558,152 @@ static const struct alg_test_desc alg_test_descs[] = {
}, { }, {
.alg = "digest_null", .alg = "digest_null",
.test = alg_test_null, .test = alg_test_null,
}, {
.alg = "drbg_nopr_ctr_aes128",
.test = alg_test_drbg,
.fips_allowed = 1,
.suite = {
.drbg = {
.vecs = drbg_nopr_ctr_aes128_tv_template,
.count = ARRAY_SIZE(drbg_nopr_ctr_aes128_tv_template)
}
}
}, {
.alg = "drbg_nopr_ctr_aes192",
.test = alg_test_drbg,
.fips_allowed = 1,
.suite = {
.drbg = {
.vecs = drbg_nopr_ctr_aes192_tv_template,
.count = ARRAY_SIZE(drbg_nopr_ctr_aes192_tv_template)
}
}
}, {
.alg = "drbg_nopr_ctr_aes256",
.test = alg_test_drbg,
.fips_allowed = 1,
.suite = {
.drbg = {
.vecs = drbg_nopr_ctr_aes256_tv_template,
.count = ARRAY_SIZE(drbg_nopr_ctr_aes256_tv_template)
}
}
}, {
/*
* There is no need to specifically test the DRBG with every
* backend cipher -- covered by drbg_nopr_hmac_sha256 test
*/
.alg = "drbg_nopr_hmac_sha1",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_nopr_hmac_sha256",
.test = alg_test_drbg,
.fips_allowed = 1,
.suite = {
.drbg = {
.vecs = drbg_nopr_hmac_sha256_tv_template,
.count =
ARRAY_SIZE(drbg_nopr_hmac_sha256_tv_template)
}
}
}, {
/* covered by drbg_nopr_hmac_sha256 test */
.alg = "drbg_nopr_hmac_sha384",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_nopr_hmac_sha512",
.test = alg_test_null,
.fips_allowed = 1,
}, {
.alg = "drbg_nopr_sha1",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_nopr_sha256",
.test = alg_test_drbg,
.fips_allowed = 1,
.suite = {
.drbg = {
.vecs = drbg_nopr_sha256_tv_template,
.count = ARRAY_SIZE(drbg_nopr_sha256_tv_template)
}
}
}, {
/* covered by drbg_nopr_sha256 test */
.alg = "drbg_nopr_sha384",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_nopr_sha512",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_pr_ctr_aes128",
.test = alg_test_drbg,
.fips_allowed = 1,
.suite = {
.drbg = {
.vecs = drbg_pr_ctr_aes128_tv_template,
.count = ARRAY_SIZE(drbg_pr_ctr_aes128_tv_template)
}
}
}, {
/* covered by drbg_pr_ctr_aes128 test */
.alg = "drbg_pr_ctr_aes192",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_pr_ctr_aes256",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_pr_hmac_sha1",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_pr_hmac_sha256",
.test = alg_test_drbg,
.fips_allowed = 1,
.suite = {
.drbg = {
.vecs = drbg_pr_hmac_sha256_tv_template,
.count = ARRAY_SIZE(drbg_pr_hmac_sha256_tv_template)
}
}
}, {
/* covered by drbg_pr_hmac_sha256 test */
.alg = "drbg_pr_hmac_sha384",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_pr_hmac_sha512",
.test = alg_test_null,
.fips_allowed = 1,
}, {
.alg = "drbg_pr_sha1",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_pr_sha256",
.test = alg_test_drbg,
.fips_allowed = 1,
.suite = {
.drbg = {
.vecs = drbg_pr_sha256_tv_template,
.count = ARRAY_SIZE(drbg_pr_sha256_tv_template)
}
}
}, {
/* covered by drbg_pr_sha256 test */
.alg = "drbg_pr_sha384",
.fips_allowed = 1,
.test = alg_test_null,
}, {
.alg = "drbg_pr_sha512",
.fips_allowed = 1,
.test = alg_test_null,
}, { }, {
.alg = "ecb(__aes-aesni)", .alg = "ecb(__aes-aesni)",
.test = alg_test_null, .test = alg_test_null,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment