Message ID | 12396284.QuoJzrrf7p@positron.chronox.de (mailing list archive) |
---|---|
State | Not Applicable |
Delegated to: | Herbert Xu |
Headers | show |
Series | /dev/random - a new approach with full SP800-90B | expand |
On 1/15/20 2:33 AM, Stephan Müller wrote: > > CC: "Eric W. Biederman" <ebiederm@xmission.com> > CC: "Alexander E. Patrakov" <patrakov@gmail.com> > CC: "Ahmed S. Darwish" <darwish.07@gmail.com> > CC: "Theodore Y. Ts'o" <tytso@mit.edu> > CC: Willy Tarreau <w@1wt.eu> > CC: Matthew Garrett <mjg59@srcf.ucam.org> > CC: Vito Caputo <vcaputo@pengaru.com> > CC: Andreas Dilger <adilger.kernel@dilger.ca> > CC: Jan Kara <jack@suse.cz> > CC: Ray Strode <rstrode@redhat.com> > CC: William Jon McCann <mccann@jhu.edu> > CC: zhangjs <zachary@baishancloud.com> > CC: Andy Lutomirski <luto@kernel.org> > CC: Florian Weimer <fweimer@redhat.com> > CC: Lennart Poettering <mzxreary@0pointer.de> > CC: Nicolai Stange <nstange@suse.de> > Reviewed-by: Roman Drahtmueller <draht@schaltsekun.de> > Tested-by: Roman Drahtmüller <draht@schaltsekun.de> > Tested-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com> > Tested-by: Neil Horman <nhorman@redhat.com> > Signed-off-by: Stephan Mueller <smueller@chronox.de> > --- > drivers/char/lrng/Kconfig | 11 ++ > drivers/char/lrng/Makefile | 1 + > drivers/char/lrng/lrng_drbg.c | 260 ++++++++++++++++++++++++++++++++++ > 3 files changed, 272 insertions(+) > create mode 100644 drivers/char/lrng/lrng_drbg.c > > diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig > index cb701bb0b8b6..15fb623d9d1f 100644 > --- a/drivers/char/lrng/Kconfig > +++ b/drivers/char/lrng/Kconfig > @@ -71,4 +71,15 @@ menuconfig LRNG_DRNG_SWITCH > accessible via the external interfaces. With this configuration > option other DRNGs can be selected and loaded at runtime. > > +if LRNG_DRNG_SWITCH > +config LRNG_DRBG > + tristate "SP800-90A support for the LRNG" > + select CRYPTO_DRBG_MENU > + select CRYPTO_CMAC if CRYPTO_DRBG_CTR Don't select these if CRYPTO is not already set/enabled. It causes Kconfig warnings and possible build errors. > + help > + Enable the SP800-90A DRBG support for the LRNG. Once the > + module is loaded, output from /dev/random, /dev/urandom, > + getrandom(2), or get_random_bytes is provided by a DRBG. > +endif # LRNG_DRNG_SWITCH > + > endif # LRNG > diff --git a/drivers/char/lrng/lrng_drbg.c b/drivers/char/lrng/lrng_drbg.c > new file mode 100644 > index 000000000000..8bf2badb1fe0 > --- /dev/null > +++ b/drivers/char/lrng/lrng_drbg.c > @@ -0,0 +1,260 @@ > +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause > +/* > + * Backend for the LRNG providing the cryptographic primitives using the > + * kernel crypto API and its DRBG. > + * > + * Copyright (C) 2016 - 2020, Stephan Mueller <smueller@chronox.de> > + */ > + > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > + > +#include <crypto/drbg.h> > +#include <linux/init.h> > +#include <linux/module.h> > +#include <linux/lrng.h> > + > +/* > + * Define a DRBG plus a hash / MAC used to extract data from the entropy pool. > + * For LRNG_HASH_NAME you can use a hash or a MAC (HMAC or CMAC) of your choice > + * (Note, you should use the suggested selections below -- using SHA-1 or MD5 > + * is not wise). The idea is that the used cipher primitive can be selected to > + * be the same as used for the DRBG. I.e. the LRNG only uses one cipher > + * primitive using the same cipher implementation with the options offered in > + * the following. This means, if the CTR DRBG is selected and AES-NI is present, > + * both the CTR DRBG and the selected cmac(aes) use AES-NI. > + * > + * The security strengths of the DRBGs are all 256 bits according to > + * SP800-57 section 5.6.1. > + * > + * This definition is allowed to be changed. > + */ > +#ifdef CONFIG_CRYPTO_DRBG_CTR > +static unsigned int lrng_drbg_type = 0; > +#elif defined CONFIG_CRYPTO_DRBG_HMAC > +static unsigned int lrng_drbg_type = 1; > +#elif defined CONFIG_CRYPTO_DRBG_HASH > +static unsigned int lrng_drbg_type = 2; > +#else > +#error "Unknown DRBG in use" > +#endif > + > +/* The parameter must be r/o in sysfs as otherwise races appear. */ > +module_param(lrng_drbg_type, uint, 0444); > +MODULE_PARM_DESC(lrng_drbg_type, "DRBG type used for LRNG (0->CTR_DRBG, " > + "1->HMAC_DRBG, 2->Hash_DRBG)"); One line for the string, please, not split.
Am Donnerstag, 16. Januar 2020, 01:14:35 CET schrieb Randy Dunlap: Hi Randy, > On 1/15/20 2:33 AM, Stephan Müller wrote: > > CC: "Eric W. Biederman" <ebiederm@xmission.com> > > CC: "Alexander E. Patrakov" <patrakov@gmail.com> > > CC: "Ahmed S. Darwish" <darwish.07@gmail.com> > > CC: "Theodore Y. Ts'o" <tytso@mit.edu> > > CC: Willy Tarreau <w@1wt.eu> > > CC: Matthew Garrett <mjg59@srcf.ucam.org> > > CC: Vito Caputo <vcaputo@pengaru.com> > > CC: Andreas Dilger <adilger.kernel@dilger.ca> > > CC: Jan Kara <jack@suse.cz> > > CC: Ray Strode <rstrode@redhat.com> > > CC: William Jon McCann <mccann@jhu.edu> > > CC: zhangjs <zachary@baishancloud.com> > > CC: Andy Lutomirski <luto@kernel.org> > > CC: Florian Weimer <fweimer@redhat.com> > > CC: Lennart Poettering <mzxreary@0pointer.de> > > CC: Nicolai Stange <nstange@suse.de> > > Reviewed-by: Roman Drahtmueller <draht@schaltsekun.de> > > Tested-by: Roman Drahtmüller <draht@schaltsekun.de> > > Tested-by: Marcelo Henrique Cerri <marcelo.cerri@canonical.com> > > Tested-by: Neil Horman <nhorman@redhat.com> > > Signed-off-by: Stephan Mueller <smueller@chronox.de> > > --- > > > > drivers/char/lrng/Kconfig | 11 ++ > > drivers/char/lrng/Makefile | 1 + > > drivers/char/lrng/lrng_drbg.c | 260 ++++++++++++++++++++++++++++++++++ > > 3 files changed, 272 insertions(+) > > create mode 100644 drivers/char/lrng/lrng_drbg.c > > > > diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig > > index cb701bb0b8b6..15fb623d9d1f 100644 > > --- a/drivers/char/lrng/Kconfig > > +++ b/drivers/char/lrng/Kconfig > > @@ -71,4 +71,15 @@ menuconfig LRNG_DRNG_SWITCH > > > > accessible via the external interfaces. With this configuration > > option other DRNGs can be selected and loaded at runtime. > > > > +if LRNG_DRNG_SWITCH > > +config LRNG_DRBG > > + tristate "SP800-90A support for the LRNG" > > + select CRYPTO_DRBG_MENU > > + select CRYPTO_CMAC if CRYPTO_DRBG_CTR > > Don't select these if CRYPTO is not already set/enabled. > It causes Kconfig warnings and possible build errors. I added "depends on CRYPTO" > > > + help > > + Enable the SP800-90A DRBG support for the LRNG. Once the > > + module is loaded, output from /dev/random, /dev/urandom, > > + getrandom(2), or get_random_bytes is provided by a DRBG. > > +endif # LRNG_DRNG_SWITCH > > + > > > > endif # LRNG > > > > diff --git a/drivers/char/lrng/lrng_drbg.c b/drivers/char/lrng/lrng_drbg.c > > new file mode 100644 > > index 000000000000..8bf2badb1fe0 > > --- /dev/null > > +++ b/drivers/char/lrng/lrng_drbg.c > > @@ -0,0 +1,260 @@ > > +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause > > +/* > > + * Backend for the LRNG providing the cryptographic primitives using the > > + * kernel crypto API and its DRBG. > > + * > > + * Copyright (C) 2016 - 2020, Stephan Mueller <smueller@chronox.de> > > + */ > > + > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > > + > > +#include <crypto/drbg.h> > > +#include <linux/init.h> > > +#include <linux/module.h> > > +#include <linux/lrng.h> > > + > > +/* > > + * Define a DRBG plus a hash / MAC used to extract data from the entropy > > pool. + * For LRNG_HASH_NAME you can use a hash or a MAC (HMAC or CMAC) > > of your choice + * (Note, you should use the suggested selections below > > -- using SHA-1 or MD5 + * is not wise). The idea is that the used cipher > > primitive can be selected to + * be the same as used for the DRBG. I.e. > > the LRNG only uses one cipher + * primitive using the same cipher > > implementation with the options offered in + * the following. This means, > > if the CTR DRBG is selected and AES-NI is present, + * both the CTR DRBG > > and the selected cmac(aes) use AES-NI. > > + * > > + * The security strengths of the DRBGs are all 256 bits according to > > + * SP800-57 section 5.6.1. > > + * > > + * This definition is allowed to be changed. > > + */ > > +#ifdef CONFIG_CRYPTO_DRBG_CTR > > +static unsigned int lrng_drbg_type = 0; > > +#elif defined CONFIG_CRYPTO_DRBG_HMAC > > +static unsigned int lrng_drbg_type = 1; > > +#elif defined CONFIG_CRYPTO_DRBG_HASH > > +static unsigned int lrng_drbg_type = 2; > > +#else > > +#error "Unknown DRBG in use" > > +#endif > > + > > +/* The parameter must be r/o in sysfs as otherwise races appear. */ > > +module_param(lrng_drbg_type, uint, 0444); > > +MODULE_PARM_DESC(lrng_drbg_type, "DRBG type used for LRNG (0->CTR_DRBG, " > > + "1->HMAC_DRBG, 2->Hash_DRBG)"); > > One line for the string, please, not split. Changed Thank you. Ciao Stephan
diff --git a/drivers/char/lrng/Kconfig b/drivers/char/lrng/Kconfig index cb701bb0b8b6..15fb623d9d1f 100644 --- a/drivers/char/lrng/Kconfig +++ b/drivers/char/lrng/Kconfig @@ -71,4 +71,15 @@ menuconfig LRNG_DRNG_SWITCH accessible via the external interfaces. With this configuration option other DRNGs can be selected and loaded at runtime. +if LRNG_DRNG_SWITCH +config LRNG_DRBG + tristate "SP800-90A support for the LRNG" + select CRYPTO_DRBG_MENU + select CRYPTO_CMAC if CRYPTO_DRBG_CTR + help + Enable the SP800-90A DRBG support for the LRNG. Once the + module is loaded, output from /dev/random, /dev/urandom, + getrandom(2), or get_random_bytes is provided by a DRBG. +endif # LRNG_DRNG_SWITCH + endif # LRNG diff --git a/drivers/char/lrng/Makefile b/drivers/char/lrng/Makefile index 31cfe87c999e..0d320fcb7b9e 100644 --- a/drivers/char/lrng/Makefile +++ b/drivers/char/lrng/Makefile @@ -11,3 +11,4 @@ obj-y += lrng_pool.o lrng_aux.o \ obj-$(CONFIG_NUMA) += lrng_numa.o obj-$(CONFIG_SYSCTL) += lrng_proc.o obj-$(CONFIG_LRNG_DRNG_SWITCH) += lrng_switch.o +obj-$(CONFIG_LRNG_DRBG) += lrng_drbg.o diff --git a/drivers/char/lrng/lrng_drbg.c b/drivers/char/lrng/lrng_drbg.c new file mode 100644 index 000000000000..8bf2badb1fe0 --- /dev/null +++ b/drivers/char/lrng/lrng_drbg.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause +/* + * Backend for the LRNG providing the cryptographic primitives using the + * kernel crypto API and its DRBG. + * + * Copyright (C) 2016 - 2020, Stephan Mueller <smueller@chronox.de> + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <crypto/drbg.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/lrng.h> + +/* + * Define a DRBG plus a hash / MAC used to extract data from the entropy pool. + * For LRNG_HASH_NAME you can use a hash or a MAC (HMAC or CMAC) of your choice + * (Note, you should use the suggested selections below -- using SHA-1 or MD5 + * is not wise). The idea is that the used cipher primitive can be selected to + * be the same as used for the DRBG. I.e. the LRNG only uses one cipher + * primitive using the same cipher implementation with the options offered in + * the following. This means, if the CTR DRBG is selected and AES-NI is present, + * both the CTR DRBG and the selected cmac(aes) use AES-NI. + * + * The security strengths of the DRBGs are all 256 bits according to + * SP800-57 section 5.6.1. + * + * This definition is allowed to be changed. + */ +#ifdef CONFIG_CRYPTO_DRBG_CTR +static unsigned int lrng_drbg_type = 0; +#elif defined CONFIG_CRYPTO_DRBG_HMAC +static unsigned int lrng_drbg_type = 1; +#elif defined CONFIG_CRYPTO_DRBG_HASH +static unsigned int lrng_drbg_type = 2; +#else +#error "Unknown DRBG in use" +#endif + +/* The parameter must be r/o in sysfs as otherwise races appear. */ +module_param(lrng_drbg_type, uint, 0444); +MODULE_PARM_DESC(lrng_drbg_type, "DRBG type used for LRNG (0->CTR_DRBG, " + "1->HMAC_DRBG, 2->Hash_DRBG)"); + +struct lrng_drbg { + const char *hash_name; + const char *drbg_core; +}; + +static const struct lrng_drbg lrng_drbg_types[] = { + { /* CTR_DRBG with AES-256 using derivation function */ + .hash_name = "cmac(aes)", + .drbg_core = "drbg_nopr_ctr_aes256", + }, { /* HMAC_DRBG with SHA-512 */ + .hash_name = "sha512", + .drbg_core = "drbg_nopr_hmac_sha512", + }, { /* Hash_DRBG with SHA-512 using derivation function */ + .hash_name = "sha512", + .drbg_core = "drbg_nopr_sha512" + } +}; + +struct lrng_hash_info { + struct shash_desc shash; + char ctx[]; +}; + +static int lrng_drbg_drng_seed_helper(void *drng, const u8 *inbuf, u32 inbuflen) +{ + struct drbg_state *drbg = (struct drbg_state *)drng; + LIST_HEAD(seedlist); + struct drbg_string data; + int ret; + + drbg_string_fill(&data, inbuf, inbuflen); + list_add_tail(&data.list, &seedlist); + ret = drbg->d_ops->update(drbg, &seedlist, drbg->seeded); + + if (ret >= 0) + drbg->seeded = true; + + return ret; +} + +static int lrng_drbg_drng_generate_helper(void *drng, u8 *outbuf, u32 outbuflen) +{ + struct drbg_state *drbg = (struct drbg_state *)drng; + + return drbg->d_ops->generate(drbg, outbuf, outbuflen, NULL); +} + +static void *lrng_drbg_drng_alloc(u32 sec_strength) +{ + struct drbg_state *drbg; + int coreref = -1; + bool pr = false; + int ret; + + drbg_convert_tfm_core(lrng_drbg_types[lrng_drbg_type].drbg_core, + &coreref, &pr); + if (coreref < 0) + return ERR_PTR(-EFAULT); + + drbg = kzalloc(sizeof(struct drbg_state), GFP_KERNEL); + if (!drbg) + return ERR_PTR(-ENOMEM); + + drbg->core = &drbg_cores[coreref]; + drbg->seeded = false; + ret = drbg_alloc_state(drbg); + if (ret) + goto err; + + if (sec_strength > drbg_sec_strength(drbg->core->flags)) { + pr_err("Security strength of DRBG (%u bits) lower than " + "requested by LRNG (%u bits)\n", + drbg_sec_strength(drbg->core->flags) * 8, + sec_strength * 8); + goto dealloc; + } + + if (sec_strength < drbg_sec_strength(drbg->core->flags)) + pr_warn("Security strength of DRBG (%u bits) higher than " + "requested by LRNG (%u bits)\n", + drbg_sec_strength(drbg->core->flags) * 8, + sec_strength * 8); + + pr_info("DRBG with %s core allocated\n", drbg->core->backend_cra_name); + + return drbg; + +dealloc: + if (drbg->d_ops) + drbg->d_ops->crypto_fini(drbg); + drbg_dealloc_state(drbg); +err: + kfree(drbg); + return ERR_PTR(-EINVAL); +} + +static void lrng_drbg_drng_dealloc(void *drng) +{ + struct drbg_state *drbg = (struct drbg_state *)drng; + + drbg_dealloc_state(drbg); + kzfree(drbg); + pr_info("DRBG deallocated\n"); +} + +static void *lrng_drbg_hash_alloc(const u8 *key, u32 keylen) +{ + struct lrng_hash_info *lrng_hash; + struct crypto_shash *tfm; + int size, ret; + + tfm = crypto_alloc_shash(lrng_drbg_types[lrng_drbg_type].hash_name, + 0, 0); + if (IS_ERR(tfm)) { + pr_err("could not allocate hash %s\n", + lrng_drbg_types[lrng_drbg_type].hash_name); + return ERR_CAST(tfm); + } + + size = sizeof(struct lrng_hash_info) + crypto_shash_descsize(tfm); + lrng_hash = kmalloc(size, GFP_KERNEL); + if (!lrng_hash) { + crypto_free_shash(tfm); + return ERR_PTR(-ENOMEM); + } + + lrng_hash->shash.tfm = tfm; + + /* If the used hash is no MAC, ignore the ENOSYS return code */ + ret = crypto_shash_setkey(tfm, key, keylen); + if (ret && ret != -ENOSYS) { + pr_err("could not set the key for MAC\n"); + crypto_free_shash(tfm); + kfree(lrng_hash); + return ERR_PTR(ret); + } + + pr_info("Hash %s allocated\n", + lrng_drbg_types[lrng_drbg_type].hash_name); + + return lrng_hash; +} + +static void lrng_drbg_hash_dealloc(void *hash) +{ + struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash; + struct shash_desc *shash = &lrng_hash->shash; + struct crypto_shash *tfm = shash->tfm; + + crypto_free_shash(tfm); + kfree(lrng_hash); + pr_info("Hash deallocated\n"); +} + +static u32 lrng_drbg_hash_digestsize(void *hash) +{ + struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash; + struct shash_desc *shash = &lrng_hash->shash; + + return crypto_shash_digestsize(shash->tfm); +} + +static int lrng_drbg_hash_buffer(void *hash, const u8 *inbuf, u32 inbuflen, + u8 *digest) +{ + struct lrng_hash_info *lrng_hash = (struct lrng_hash_info *)hash; + struct shash_desc *shash = &lrng_hash->shash; + + return crypto_shash_digest(shash, inbuf, inbuflen, digest); +} + +static const char *lrng_drbg_name(void) +{ + return lrng_drbg_types[lrng_drbg_type].drbg_core; +} + +static const char *lrng_hash_name(void) +{ + return lrng_drbg_types[lrng_drbg_type].hash_name; +} + +const static struct lrng_crypto_cb lrng_drbg_crypto_cb = { + .lrng_drng_name = lrng_drbg_name, + .lrng_hash_name = lrng_hash_name, + .lrng_drng_alloc = lrng_drbg_drng_alloc, + .lrng_drng_dealloc = lrng_drbg_drng_dealloc, + .lrng_drng_seed_helper = lrng_drbg_drng_seed_helper, + .lrng_drng_generate_helper = lrng_drbg_drng_generate_helper, + .lrng_hash_alloc = lrng_drbg_hash_alloc, + .lrng_hash_dealloc = lrng_drbg_hash_dealloc, + .lrng_hash_digestsize = lrng_drbg_hash_digestsize, + .lrng_hash_buffer = lrng_drbg_hash_buffer, +}; + +static int __init lrng_drbg_init(void) +{ + if (lrng_drbg_type >= ARRAY_SIZE(lrng_drbg_types)) { + pr_err("lrng_drbg_type parameter too large (given %u - max: %lu)", + lrng_drbg_type, + (unsigned long)ARRAY_SIZE(lrng_drbg_types) - 1); + return -EAGAIN; + } + return lrng_set_drng_cb(&lrng_drbg_crypto_cb); +} + +static void __exit lrng_drbg_exit(void) +{ + lrng_set_drng_cb(NULL); +} + +late_initcall(lrng_drbg_init); +module_exit(lrng_drbg_exit); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Stephan Mueller <smueller@chronox.de>"); +MODULE_DESCRIPTION("Linux Random Number Generator - SP800-90A DRBG backend");